多数据源 数据源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. c++程序—布尔值

    #include<iostream> using namespace std; #include<string> int main() { //创建bool数据类型 bool ...

  2. ping.sh

    扫描整个网段  nmap -sP 10.0.0.0/24 #!/bin/bash ps () { ping $1 -c 3 -w 2 |grep -q "ttl"      #结果 ...

  3. springboot + shiro+登录 微信登录 次数验证资料

    分享一个朋友的人工智能教程.零基础!通俗易懂!风趣幽默!大家可以看看是否对自己有帮助,点击查看教程. 1.https://blog.csdn.net/xtiawxf/article/details/5 ...

  4. Standard Aras Dialogs

    In a another blog post, we covered how to open dialogs within Aras Innovator using custom forms and ...

  5. 一小时搞定Eureka

    一.什么是Eureka Eureka是Netflix公司开源的产品,它是一种基于REST( Representational State Transfer )的服务,主要用于AWS云. Eureka提 ...

  6. springboot 潜入式web容器

    普通servlet 容器 1.tomcat <dependency> <groupId>org.springframework.boot</groupId> < ...

  7. Redis: Reducing Memory Usage

    High Level Tips for Redis Most of Stream-Framework's users start out with Redis and eventually move ...

  8. CountUp.js 数字跳转效果小插件

    CountUp.js  实现数字跳转效果的小插件 //调用方法 const easingFn = function (t, b, c, d) { var ts = (t /= d) * t; var ...

  9. vue 中使用 vue-fullpage

    安装并使用 安装 npm install --save vue-fullpage.js 引入 // 引用fullpage 插件 import Vue from 'vue' import 'fullpa ...

  10. 在java中如何根据手机号查询号码归属地

    1.maven项目中配置 <dependency><groupId>com.googlecode.libphonenumber</groupId><artif ...