基于redis实现锁控制
多数据源 数据源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());
}
}
基于redis实现锁控制的更多相关文章
- RedLock.Net - 基于Redis分布式锁的开源实现
工作中,经常会遇到分布式环境中资源访问冲突问题,比如商城的库存数量处理,或者某个事件的原子性操作,都需要确保某个时间段内只有一个线程在访问或处理资源. 因此现在网上也有很多的分布式锁的解决方案,有数据 ...
- 基于Redis分布式锁的正确打开方式
分布式锁是在分布式环境下(多个JVM进程)控制多个客户端对某一资源的同步访问的一种实现,与之相对应的是线程锁,线程锁控制的是同一个JVM进程内多个线程之间的同步.分布式锁的一般实现方法是在应用服务器之 ...
- Redis并发锁控制
为了防止用户在页面上重复点击或者同时发起多次请求,请求处理需要操作redis缓存,这个时候需要对并发边界进行并发锁控制,实现思路: 由于每个页面发起的请求带的token具备唯一性,可以将token作为 ...
- 基于Redis分布式锁(获取锁及解锁)
目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency).可用性( ...
- c# 基于redis分布式锁
在单进程的系统中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量. 而同步的本质是通过锁来实现的.为了实现多个线程在 ...
- 基于redis分布式锁实现“秒杀”
转载:http://blog.5ibc.net/p/28883.html 最近在项目中遇到了类似“秒杀”的业务场景,在本篇博客中,我将用一个非常简单的demo,阐述实现所谓“秒杀”的基本思路. 业务场 ...
- 基于redis分布式锁实现“秒杀”(转载)
转载:http://blog.csdn.net/u010359884/article/details/50310387 最近在项目中遇到了类似“秒杀”的业务场景,在本篇博客中,我将用一个非常简单的de ...
- 基于 Redis 分布式锁
1.主流分布式锁实现方案 基于数据库实现分布式锁 基于缓存(redis 等) 基于 Zookeeper 2.根据实现方式分类 : 类 CAS 自旋式分布式锁:询问的方式,类似 java 并发编程中的线 ...
- 基于Redis的分布式锁真的安全吗?
说明: 我前段时间写了一篇用consul实现分布式锁,感觉理解的也不是很好,直到我看到了这2篇写分布式锁的讨论,真的是很佩服作者严谨的态度, 把这种分布式锁研究的这么透彻,作者这种技术态度真的值得我好 ...
随机推荐
- 【LeetCode】解码方法
[问题] 一条包含字母 A-Z 的消息通过以下方式进行了编码:'A' -> 1'B' -> 2…'Z' -> 26给定一个只包含数字的非空字符串,请计算解码方法的总数. 示例 : 输 ...
- 大二暑假第二周总结--开始学习Hadoop基础(一)
一.简单视频学习Hadoop的处理架构 二.简单视频学习分布式文件系统HDFS并进行简单的实践操作 简单操作教程:http://dblab.xmu.edu.cn/blog/290-2/ 注意:在建立H ...
- 十八、CI框架之数据库操作update用法
一.代码如图: 二.访问一下 三.我们来查看数据库,已经被修改了 不忘初心,如果您认为这篇文章有价值,认同作者的付出,可以微信二维码打赏任意金额给作者(微信号:382477247)哦,谢谢.
- Spring学习(三)——@PropertySource,@ImportResource,@Bean注解
@PropertySource注解是将配置文件中 的值赋值给POJO 项目结构如下 一.创建一个Person.Java文件: import org.springframework.boot.conte ...
- SublimeText3和插件的安装
SublimeText3和插件的安装 步骤一:进入官网下载SublimeText3(http://www.sublimetext.com/3),安装并打开SublimeText3 步骤二:进入Su ...
- Android进阶——多线程系列之wait、notify、sleep、join、yield、synchronized关键字、ReentrantLock锁
多线程一直是初学者最困惑的地方,每次看到一篇文章,觉得很有难度,就马上叉掉,不看了,我以前也是这样过来的.后来,我发现这样的态度不行,知难而退,永远进步不了.于是,我狠下心来看完别人的博客,尽管很难但 ...
- org.springframework.test.context.junit4.SpringJUnit4ClassRunner
项目中有了spring-test的依赖,里面确实也有 org.springframework.test.context.junit4.SpringJUnit4ClassRunner 此类,但是项目就是 ...
- 第21章—websocket
spring boot 系列学习记录:http://www.cnblogs.com/jinxiaohang/p/8111057.html 码云源码地址:https://gitee.com/jinxia ...
- APP测试关注的点 - 笔记
来源公开课笔记!!! 1.黑盒测试 是否正确并如设计的一样正常运行.测试自动化回归测试 2.测试主要关注参数: CPU.内存.耗电量.流量.FRS(流畅度).同时关注APP安装耗时和启动耗时 3.适配 ...
- Python自学之路---Day01
目录 Python自学之路---Day01 注释 单行注释 多行注释 print()函数 语法 参数 实例 input()函数 语法 参数 实例 查看Python的关键字 代码 变量与常量 变量 如何 ...