多数据源 数据源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实现锁控制的更多相关文章

  1. RedLock.Net - 基于Redis分布式锁的开源实现

    工作中,经常会遇到分布式环境中资源访问冲突问题,比如商城的库存数量处理,或者某个事件的原子性操作,都需要确保某个时间段内只有一个线程在访问或处理资源. 因此现在网上也有很多的分布式锁的解决方案,有数据 ...

  2. 基于Redis分布式锁的正确打开方式

    分布式锁是在分布式环境下(多个JVM进程)控制多个客户端对某一资源的同步访问的一种实现,与之相对应的是线程锁,线程锁控制的是同一个JVM进程内多个线程之间的同步.分布式锁的一般实现方法是在应用服务器之 ...

  3. Redis并发锁控制

    为了防止用户在页面上重复点击或者同时发起多次请求,请求处理需要操作redis缓存,这个时候需要对并发边界进行并发锁控制,实现思路: 由于每个页面发起的请求带的token具备唯一性,可以将token作为 ...

  4. 基于Redis分布式锁(获取锁及解锁)

    目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency).可用性( ...

  5. c# 基于redis分布式锁

    在单进程的系统中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量. 而同步的本质是通过锁来实现的.为了实现多个线程在 ...

  6. 基于redis分布式锁实现“秒杀”

    转载:http://blog.5ibc.net/p/28883.html 最近在项目中遇到了类似“秒杀”的业务场景,在本篇博客中,我将用一个非常简单的demo,阐述实现所谓“秒杀”的基本思路. 业务场 ...

  7. 基于redis分布式锁实现“秒杀”(转载)

    转载:http://blog.csdn.net/u010359884/article/details/50310387 最近在项目中遇到了类似“秒杀”的业务场景,在本篇博客中,我将用一个非常简单的de ...

  8. 基于 Redis 分布式锁

    1.主流分布式锁实现方案 基于数据库实现分布式锁 基于缓存(redis 等) 基于 Zookeeper 2.根据实现方式分类 : 类 CAS 自旋式分布式锁:询问的方式,类似 java 并发编程中的线 ...

  9. 基于Redis的分布式锁真的安全吗?

    说明: 我前段时间写了一篇用consul实现分布式锁,感觉理解的也不是很好,直到我看到了这2篇写分布式锁的讨论,真的是很佩服作者严谨的态度, 把这种分布式锁研究的这么透彻,作者这种技术态度真的值得我好 ...

随机推荐

  1. 081-PHP的do-while循环

    <?php $i = 1; do { echo $i; $i = $i +1; } while ($i <= 8); ?>

  2. C++ for无限循环~

    无限循环 如果条件永远不为假,则循环将变成无限循环.for 循环在传统意义上可用于实现无限循环.由于构成循环的三个表达式中任何一个都不是必需的,您可以将某些条件表达式留空来构成一个无限循环. #inc ...

  3. AIDL使用绑定启动远程Service出现Service Intent must be explicit: Intent

    Intent intent = new Intent(); intent.setAction("remote.MyRemoteService.Action"); 使用AIDL调用远 ...

  4. C#数据库查询和操作大全

    一:C#数据库查询之数据库连接代码: SqlConnectionobjSqlConnection=newSqlConnection("server=127.0.0.1;uid=sa;pwd= ...

  5. kafka创建topic,生产和消费指定topic消息

    启动zookeeper和Kafka之后,进入kafka目录(安装/启动kafka参考前面一章:https://www.cnblogs.com/cici20166/p/9425613.html) 1.创 ...

  6. stl 题目总结

    stl 题目总结 一.圆桌问题 1 .问题: 圆桌上围坐着2n个人.其中n个人是好人,另外n个人是坏人.如果从第一个人开始数数,数到第m个人,则立即处死该人:然后从被处死的人之后开始数数,再将数到的第 ...

  7. ..\EEP\EEP.c(249): error: #268: declaration may not appear after executable statement in block

    主要原因:  ON_nWP;这个应该放在 unsigned char Delay; unsigned char ReData; 的后面. 修改成功.

  8. bzoj 4236JOIOJI

    一开始忘掉特殊情况也是蛋疼2333(有一直到头的.mp[0][0]是要特判的) 做法也就是找mp[i][j]相同的东西.(貌似可以写成线性方程组(z=x+A,z=y+B)过这个的就是相等(可以先从2维 ...

  9. 【5分钟+】计算机系统结构:CPU性能公式

    计算机系统结构:CPU性能公式 基础知识 CPU 时间:一个程序在 CPU 上运行的时间.(不包括I/O时间) 主频.时钟频率:CPU 内部主时钟的频率,表示1秒可以完成多少个周期. 例如,主频为 4 ...

  10. Thread.currentThread()和this的区别

    1. Thread.currentThread()可以获取当前线程的引用,一般都是在没有线程对象又需要获得线程信息时通过Thread.currentThread()获取当前代码段所在线程的引用. 2. ...