多数据源 数据源1为锁控制,数据源2自定义,可用于存储。

  锁:当出现并发的时候为了保证数据的一致性,不会出现并发问题,假设,用户1修改一条信息,用户2也同时修改,会按照顺序覆盖自修改的值,为了避免这种情况的发生,使用redis锁,实现控制。只可以一个用户去修改那条数据,当出现多个用户,会报错,抛出异常提示。

依赖:

<dependencies>
<!--######################### 定义 redis 版本 #########################-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--######################### 定义 jedis 版本 #########################-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--######################### 定义 json 版本 #########################-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<!--######################### 定义 lang3 版本 #########################-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>

redis配置类

package cn.lsr.redis.core;

/**
* @Description: redis参数配置类
* @Package: lsr-microservice
* @author: Hacker_lsr@126.com
* @version: V1.0
**/
public class RedisPropertiesConfig {
/**
* redis 数据库
*/
private Integer database; /**
* redis 主机地址
*/
private String host; /**
* 端口
*/
private Integer port; /**
* 密码
*/
private String password; /**
* 驱动类名
*/
private Integer timeout; private Pool pool; //get set public static class Pool { private Integer maxActive; private Integer minIdle; private Integer maxIdle; private Integer maxWait; //get set
}
}

redis工厂基类:

package cn.lsr.redis.core;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig; import java.time.Duration; /**
* @Description: redis配置基类
* @Package: lsr-microservice
* @author: Hacker_lsr@126.com
* @version: V1.0
**/
public class LSRBaseRedisConfig {
/**
* jedis 连接工厂
* @param redisPropertiesConfig
* @return
*/
public JedisConnectionFactory buildJedisConnectionFactory(RedisPropertiesConfig redisPropertiesConfig) {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setDatabase(redisPropertiesConfig.getDatabase());
jedisConnectionFactory.setHostName(redisPropertiesConfig.getHost());
jedisConnectionFactory.setPort(redisPropertiesConfig.getPort());
jedisConnectionFactory.setPassword(redisPropertiesConfig.getPassword());
jedisConnectionFactory.setTimeout(redisPropertiesConfig.getTimeout()); JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(redisPropertiesConfig.getPool().getMaxIdle());
poolConfig.setMinIdle(redisPropertiesConfig.getPool().getMinIdle());
poolConfig.setMaxTotal(redisPropertiesConfig.getPool().getMaxActive());
poolConfig.setMaxWaitMillis(redisPropertiesConfig.getPool().getMaxWait());
poolConfig.setTestOnBorrow(true); jedisConnectionFactory.setPoolConfig(poolConfig);
return jedisConnectionFactory; }
private Duration timeToLive = Duration.ZERO;
public void setTimeToLive(Duration timeToLive) {
this.timeToLive = timeToLive;
} /**
* 缓存
* @param factory
* @return
*/
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题)
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(timeToLive)
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
//
// RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
// return redisCacheManager;
//} /**
* RedisTemplate 初始化 序列化和反序列化
* @param redisConnectionFactory
* @return
*/
public RedisTemplate buidRedisTemplate(RedisConnectionFactory redisConnectionFactory) { /* Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(redisConnectionFactory);
//template.setKeySerializer(jackson2JsonRedisSerializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
*/
RedisSerializer stringSerializer = new StringRedisSerializer();
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);
return redisTemplate;
}
}

数据库操作工厂:

package cn.lsr.redis.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; /**
* @Description: 数据操作redis配置
* @Package: lsr-microservice
* @author: Hacker_lsr@126.com
* @version: V1.0
**/
@Configuration
public class LSRDBRedisConfig extends LSRBaseRedisConfig {
private static final Logger log = LoggerFactory.getLogger(LSRDBRedisConfig.class);
/**
* 初始化 jedis lsrDBRedisProperties 连接工厂 -- lsrDBJedisConnectionFactory
* @param redisPropertiesConfig
* @return
*/
@Bean(name = "lsrDBJedisConnectionFactory")
@Override
public JedisConnectionFactory buildJedisConnectionFactory(@Qualifier("lsrDBRedisProperties")RedisPropertiesConfig redisPropertiesConfig) {
log.info("lsrDBRedisConfig RedisPropertiesConfig:{}",redisPropertiesConfig);
return super.buildJedisConnectionFactory(redisPropertiesConfig);
} /**
* 初始化工厂中 lsrDBJedisConnectionFactory 的 lsrDBRedisTemplate
* @param redisConnectionFactory
* @return
*/
@Bean(name = "lsrDBRedisTemplate")
@Override
public RedisTemplate <Object, Object> buidRedisTemplate(@Qualifier("lsrDBJedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
return super.buidRedisTemplate(redisConnectionFactory);
} // @Bean
// @Override
// public CacheManager cacheManager(@Qualifier("lbsRedisTemplate")RedisTemplate redisTemplate) {
// return super.cacheManager(redisTemplate);
// } /**
* 启动加载配置文件 yml redis 连接参数
* @return
*/
@Bean(name = "lsrDBRedisProperties")
@ConfigurationProperties(prefix = "spring.redis.db")
public RedisPropertiesConfig getBaseDBProperties() {
return new RedisPropertiesConfig();
} }

锁实现工厂:

package cn.lsr.redis.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; /**
* @Description: 锁的配置
* @Package: lsr-microservice
* @author: Hacker_lsr@126.com
* @version: V1.0
**/
@Configuration
public class LSRLockRedisConfig extends LSRBaseRedisConfig {
private static final Logger log = LoggerFactory.getLogger(LSRLockRedisConfig.class); /**
* 初始化 jedis lsrLockRedisConfig 连接工厂 -- lsrLockJedisConnectionFactory
* @param redisPropertiesConfig
* @return
*/
@Primary
@Bean(name = "lsrLockJedisConnectionFactory")
@Override
public JedisConnectionFactory buildJedisConnectionFactory(@Qualifier("lsrLockRedisConfig")RedisPropertiesConfig redisPropertiesConfig) {
log.info("MasterRedisConfig RedisPropertiesConfig:{}",redisPropertiesConfig);
return super.buildJedisConnectionFactory(redisPropertiesConfig);
} /**
* 初始化工厂中 lsrLockJedisConnectionFactory 的 lsrLockRedisTemplate
* @param redisConnectionFactory
* @return
*/
@Bean(name = "lsrLockRedisTemplate")
@Override
public RedisTemplate<Object, Object> buidRedisTemplate(@Qualifier("lsrLockJedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
return super.buidRedisTemplate(redisConnectionFactory);
} // @Bean
// @Override
// public CacheManager cacheManager(@Qualifier("lbsRedisTemplate")RedisTemplate redisTemplate) {
// return super.cacheManager(redisTemplate);
// } /**
* 启动加载配置文件 yml redis 连接参数
* @return
*/
@Bean(name = "lsrLockRedisConfig")
@ConfigurationProperties(prefix = "spring.redis.lock")
public RedisPropertiesConfig getBaseDBProperties() {
return new RedisPropertiesConfig();
} }

定义redis 锁实现逻辑

package cn.lsr.redis.core;

import cn.lsr.redis.utils.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; import javax.annotation.Resource; /**
* @Description: 用redis实现分布式锁
* @Package: lsr-microservice
* @author: Hacker_lsr@126.com
* @version: V1.0
**/
@Component
public class RedisLock {
/**
* 不写默认使用带有@Primary的lsrLockRedisTemplate
*/
@Resource(name = "lsrLockRedisTemplate")
private RedisTemplate redisTemplate;
@Resource(name = "lsrDBRedisTemplate")
private RedisTemplate redisTemplate2; /**
* 加锁
* @param key id
* @param value 时间戳
* @return
*/
public boolean lock(String key, String value) {
//setIfAbsent相当于jedis中的setnx,如果能赋值就返回true,如果已经有值了,就返回false
//即:在判断这个key是不是第一次进入这个方法
if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
//第一次,即:这个key还没有被赋值的时候
return true; }
String current_value = (String) redisTemplate.opsForValue().get(key);
if (!StringUtils.object2String(current_value).equals("")
//超时了
&& Long.parseLong(current_value) < System.currentTimeMillis()) {//①
//并发 重置value 让其获得锁失败!
redisTemplate.opsForValue().getAndSet(key, value);//②
String newValue = (String) redisTemplate.opsForValue().get(key);
if (!StringUtils.object2String(newValue).equals("")
//如果两个线程同时调用这个方法,当同时走到①的时候,
// 无论怎么样都有一个线程会先执行②这一行,
//假设线程1先执行②这行代码,那redis中key对应的value就变成了value
//然后线程2再执行②这行代码的时候,获取到的old_value就是value,
//那么value显然和他上面获取的current_value是不一样的,则线程2是没法获取锁的
&& newValue.equals(current_value)) {
return true;
}
}
return false;
} /**
* 释放锁
* @param key id
* @param value 时间戳
*/
public void unlock(String key, String value) {
try {
if (StringUtils.object2String(redisTemplate.opsForValue().get(key)).equals(value)) {
redisTemplate.opsForValue().getOperations().delete(key);
}
} catch (Exception e) {
e.printStackTrace();
}
} }

封装redis锁实现为借口:

package cn.lsr.redis.lock;

import cn.lsr.redis.utils.RedisResult;

/**
* @Description: redis接口
* @Package: lsr-microservice
* @author: Hacker_lsr@126.com
* @version: V1.0
**/
public interface RedisInterFace {
/**
* 获取锁服务
* @param id 唯一标识
* @param value 时间戳
* @return
*/
public RedisResult lock(String id, String value); /**
* 解锁服务
* @param id 唯一标识
* @param value 时间戳
*/
public RedisResult unlock(String id, String value);
}

redis锁借口实现:

package cn.lsr.redis.lock.imp;

import cn.lsr.redis.core.RedisLock;
import cn.lsr.redis.lock.RedisInterFace;
import cn.lsr.redis.utils.RedisResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; /**
* @Description: redis锁实现
* @Package: lsr-microservice
* @author: Hacker_lsr@126.com
* @version: V1.0
**/
@Service
public class RedisInterFaceImp implements RedisInterFace {
private static final Logger log = LoggerFactory.getLogger(RedisInterFaceImp.class);
@Autowired
private RedisLock redisLock;
@Override
public RedisResult lock(String id, String value) {
if (!redisLock.lock(id,value)){
log.info("获取redis失败 错误!!标识为:"+id);
return RedisResult.error(false,"获得redis锁错误!!!! 标识为:"+id);
//throw new RuntimeException("活得锁失败!");
}
log.info("获得redis锁成功 标识为:"+id);
return RedisResult.success(true,"获得redis锁成功 标识为:"+id);
} @Override
public RedisResult unlock(String id, String value) {
log.info("释放redis锁成功 标识为:"+id);
redisLock.unlock(id,value);
return RedisResult.success(true,"释放redis锁成功 标识为:"+id);
}
}

调用使用模拟

package cn.lsr.user.controller.user;

/**
* = = 用户控制器
*
* @Version: 1.0
* @Author: Hacker_lsr@126.com
*/
@Api(tags = "用户信息控制器")
@Controller
public class UserController {
private TestServerPollThread testServerPollThread;
/**
* 注入redis服务
*/
@Resource
private RedisInterFace redisInterFace; }
/**
* 功能描述: <br>
* 〈〉根据主键删除
* @Param: [uid]
* @Return: com.lsr.common.utils.Result
* @Author: Hacker_lsr@126.com
*/
@RequiresPermissions("delete")
@RequestMapping("/delete/user")
@ResponseBody
public Result deleteUser(String uid){
String time = System.currentTimeMillis()+"";
RedisResult lock = redisInterFace.lock(uid, time);
if (lock.getStatus()==200){
//userMapper.deleteByPrimaryKey(uid);
userMapper.selecTest("admin");
}else {
throw new RuntimeException(lock.getMessages());
}
RedisResult unlock = redisInterFace.unlock(uid, time);
log.info("reids锁释放:{}",unlock.getMessages());
return Result.success("操作成功");
}
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.0.104",6379);
jedis.ping();
System.out.println(jedis.ping());
}
}

最新文章

  1. lamp环境搭建(ubuntu)
  2. Robotium编写测试用例如何模拟Junit4的BeforeClass和AfterClass方法1 - 条件判断法
  3. 生理周期[PKU1006]
  4. 最全面的jdbcUtils,总有一种适合你
  5. GNU的ar,ranlib和nm
  6. POJ1046Color Me Less
  7. 如何登录mysql? cmd怎么连接mysql数据库
  8. 图数据库项目DGraph的前世今生
  9. SQL Server 存储过程的运用
  10. outline,box-shadow,border-radius小例子
  11. jmeter 启动报错:not able to find java executable or version
  12. Git配置信息相关命令
  13. Confluence 6 内存使用和需求
  14. curl解压gzip页面gzcompress内容
  15. 【Java】 大话数据结构(1) 线性表之顺序存储结构
  16. cross validation笔记
  17. Unity 如何在打包的时候执行一些逻辑
  18. 用NPOI操作EXCEL--巧妙使用Excel Chart
  19. Linux中Redis的安装
  20. WCF使用net.tcp传输文件

热门文章

  1. poi 导出Excel java代码
  2. RF:connecting to multiple databases
  3. Java算法练习—— Z 字形变换
  4. 19 01 19 视图 HttpReqeust对象 GET属性 POST属性 HttpResponse对象
  5. CF1217B Zmei Gorynich
  6. mysql初始化数据库建表脚本
  7. 82.常用的返回QuerySet对象的方法使用详解:all,select_related
  8. Windows下Nodejs的开发环境搭建
  9. centos通过yum安装php
  10. php对象:__autoload()函数及单入口文件,__set(), __get(), get_class_methods(),get_class_vars()