springboot集成redission以及分布式锁的使⽤详解⽬录
springboot集成redission及分布式锁的使⽤
1、引⼊jar包
2、增加Configuration类
3、使⽤redission分布式锁
Springboot整合Redisson 锁
⼀、依赖
⼆、配置⽂件
三、锁的使⽤
四、分布式秒杀
五、redis锁单机版可⽤,分布式⽤Redisson
springboot集成redission及分布式锁的使⽤
1、引⼊jar包
<dependency>
<groupId&disson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.4</version>
</dependency>
2、增加Configuration类
@Configuration
public class RedissonConfig {
@Value("${dis.host}")
private String host;
@Value("${dis.port}")
private String port;
@Value("${dis.password}")
private String password;
@Bean
public RedissonClient getRedisson() {
Config config = new Config();
config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password);
ate(config);
}
}
3、使⽤redission分布式锁
@Autowired
private RedissonClient redissonClient;
//⽅法区
String key = "aa:bb:cc:01";
RLock rLock =Lock(key);
try{<br>// 尝试加锁,最多等待1秒,上锁以后10秒⾃动解锁<br>// 没有Watch Dog ,10s后⾃动释放
boolean res = Lock(1,10, TimeUnit.SECONDS);
if(!res){
return new GeneralVO<>(400, "请勿重复提交", false);
}
}finally{
rLock.unlock();
}
private void redissonDoc() throws InterruptedException {
//1. 普通的可重⼊锁
RLock lock = Lock("generalLock");
// 拿锁失败时会不停的重试
// 具有Watch Dog ⾃动延期机制默认续30s 每隔30/3=10 秒续到30s
lock.lock();
// 尝试拿锁10s后停⽌重试,返回false
/
/ 具有Watch Dog ⾃动延期机制默认续30s
boolean res1 = Lock(10, TimeUnit.SECONDS);
// 拿锁失败时会不停的重试
// 没有Watch Dog ,10s后⾃动释放
lock.lock(10, TimeUnit.SECONDS);
// 尝试拿锁100s后停⽌重试,返回false
// 没有Watch Dog ,10s后⾃动释放
boolean res2 = Lock(100, 10, TimeUnit.SECONDS);
//2. 公平锁保证 Redisson 客户端线程将以其请求的顺序获得锁
RLock fairLock = FairLock("fairLock");
//3. 读写锁没错与JDK中ReentrantLock的读写锁效果⼀样
RReadWriteLock readWriteLock = ReadWriteLock("readWriteLock");
readWriteLock.writeLock().lock();
}
Springboot整合Redisson 锁
Redisson是⼀个在Redis的基础上实现的Java驻内存数据⽹格
⼀、依赖
<dependency>
<groupId&disson</groupId>
<artifactId>redisson</artifactId>
<version>3.15.4</version>
</dependency>
spring:
redis:
database: 7
host: 116.62.178.11
port: 6379
password: 1234qwer
# spring-boot 1.0默认 jedis; spring-boot2.0 默认lettuce ,lettuce线程安全
lettuce:
pool:
# 连接池中的最⼤空闲连接默认8
max-idle: 8
# 连接池中的最⼩空闲连接默认0
min-idle: 500
# 连接池最⼤连接数默认8 ,负数表⽰没有限制
max-active: 2000
# 连接池最⼤阻塞等待时间(使⽤负值表⽰没有限制)默认-1
max-wait: -1
cache:
type: redis
@Configuration
public class RedissonConfig {
@Value("${dis.host}")
private String host;
@Value("${dis.port}")
private int port;
@Value("${dis.password}")
private String password;
@Bean(destroyMethod = "shutdown")
RedissonClient redissonClient() throws IOException {
Config config = new Config();
config.useSingleServer()
.setPassword(password)
.
setAddress("redis://" + host + ":" + port).setDatabase(7);
ate(config);
}
}
三、锁的使⽤
读写锁
public class RedissionDemo {
@Autowired
private RedissonClient redissonClient;
@Autowired
private RedisTemplate redisTemplate;
/
**
* 读写锁总结
*
* 读锁⼜叫共享锁
* 写锁⼜叫排他锁(互斥锁)
* 读 + 读相当于⽆锁,并发读,同时加锁成功
* 写 + 写阻塞状态
* 写 + 读等待写锁释放
* 读 + 写等待读锁完,才写,
*/
public String writeValue() {
String str = "";
RReadWriteLock readWriteLock = ReadWriteLock("writeLock"); RLock rLock = readWriteLock.writeLock();
try {
rLock.lock();
str = UUID.randomUUID().toString();
redisTemplate.opsForValue().set("uuid", str);
Thread.sleep(30000);
} catch (Exception e) {
} finally {
rLock.unlock();
}
return str;
}
/**
* 读锁
*
* @return
*/
public String readValue() {
String str = "";
RReadWriteLock readWriteLock = ReadWriteLock("writeLock"); RLock rLock = adLock();
rLock.lock();
str = (String) redisTemplate.opsForValue().get("uuid");
rLock.unlock();
return str;
}
}
信号量
public class RedissionDemo {
@Autowired
private RedissonClient redissonClient;
@Autowired
private RedisTemplate redisTemplate;
/
**
* 信号量
*
* @return
*/
//停车⽅法
@GetMapping("/park")
public String park() throws InterruptedException {
//这⾥是获取信号量的值,这个信号量的name⼀定要与你初始化的⼀致
RSemaphore park = Semaphore("park");
//这⾥会将信号量⾥⾯的值-1,如果为0则⼀直等待,直到信号量>0
park.acquire();
//tryAcquire为⾮阻塞式等待
//Acquire();
}
public String go() throws InterruptedException {
//这⾥是获取信号量的值,这个信号量的name⼀定要与你初始化的⼀致 RSemaphore park = Semaphore("park");
//这⾥会将信号量⾥⾯的值+1,也就是释放信号量
return "ok";
}
}
闭锁
public class RedissionDemo {
@Autowired
private RedissonClient redissonClient;
@Autowired
private RedisTemplate redisTemplate;
/**
* 闭锁,限流
*
* @return
* @throws InterruptedException
*/
//锁门
public String lockdoor() throws InterruptedException {
RCountDownLatch door = CountDownLatch("door"); //设置⼀个班级有20个同学
//需要等到20个同学全部离开,才锁门
door.await();
return "锁门了";
}
public String leave(Long id) throws InterruptedException {
RCountDownLatch door = CountDownLatch("door"); //表⽰⼀个同学离开
return "" + id + "号同学离开了";
}
}
四、分布式秒杀
秒杀流程:
@Service
@Slf4j
public class DistributedSecKillBiz {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
/**
* 分布式锁。唯⼀缺点枷锁失效时间
* 枷锁院⼦操作,
* 解锁,删除锁也是原⼦操作瑕疵没有续命
*
* @return
*/
public String doKill() {
String lock = UUID.randomUUID().toString();
String goodsId = "10054";
boolean flag = redisTemplate.opsForValue().setIfAbsent(goodsId, lock, 30, TimeUnit.SECONDS);
if (flag) {
// 获取锁成功
try {
Long stock = redisTemplate.opsForValue().decrement(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId); if (stock > 0) {
redisTemplate.opsForValue().increment(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);
log.info("扣减库存成功,还剩:" + stock);
}
return "库存不⾜,该商品已抢购完!";
} catch (Exception e) {
} finally {
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
}
}
return doKill();
}
/**
* 整合 redission
* @return
*/
public String doKillDistributed() {
String goodsId = "10054";
RLock lock = Lock(upActivityKey() + SecKillConstant.LOCK + goodsId);
// 获取锁成功
try {
//1 阻塞式等待,默认30秒时间
//2 ⾃动续期,如果业务超长,续上新的30秒,不⽤担⼼过期时间,锁⾃动删除掉
//3 枷锁的业务运⾏完成,就不会给当前的锁⾃动续期,即使没有⼿动释放锁也会,30秒⾃动释放
// lock.lock(30, TimeUnit.SECONDS); //不会⾃动续期需要注意
lock.lock();
Long stock = redisTemplate.opsForValue().decrement(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId); if (stock > 0) {
redisTemplate.opsForValue().increment(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);
log.info("扣减库存成功,还剩:" + stock);
}
return "库存不⾜,该商品已抢购完!";
} catch (Exception e) {
} finally {
lock.unlock();
}
return "fail";
}
/**
* 获取活动
*
* @return
*/
public ActivityBo upActivity() {
return new ActivityBo("七⼣活动", "SEVEN_ACTIVITY", new Date(), new Date());
}
/**
* 活动公共key
*
* @return
*/
public String upActivityKey() {
return SecKillConstant.SEC_KILL + upActivity().getActivityKey() + ":";
}
}
五、redis锁单机版可⽤,分布式⽤Redisson
package com.yang.yimall.seckill.app.seckill.biz;
import org.springframework.beans.factory.annotation.Autowired;
import org.RedisTemplate;
import org.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import java.util.Collections;
spring怎么读文件import java.util.UUID;
import urrent.TimeUnit;
/**
* redis 锁集有瑕疵不能续命
*/
@Service
public class RedisLock {
@Autowired
private RedisTemplate redisTemplate;
private String lockName = "lockName";
private ThreadLocal<String> threadLocal = new ThreadLocal<>();
public void lock(String lockName) {
if (tryLock(lockName)) {
return;
}
lock(lockName);
}
public void lock() {
if (tryLock(lockName)) {
return;
}
lock();
}
/**
* 添加key 并且设置过期时间原⼦操作
*
* @param lockName
* @return
*/
public boolean tryLock(String lockName) {
String uuid = UUID.randomUUID().toString();
threadLocal.set(uuid);
return redisTemplate.opsForValue().setIfAbsent(lockName, uuid, 30, TimeUnit.SECONDS);
}
/**
* 如果查询有key,就删除,原⼦操作
*/
public void unlock() {
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
}
使⽤
public String doKillUp() {
String goodsId = "10054";
redisLock.lock(goodsId);
// 获取锁成功
try {
Long stock = redisTemplate.opsForValue().decrement(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId); if (stock > 0) {
redisTemplate.opsForValue().increment(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT
+ goodsId);
log.info("扣减库存成功,还剩:" + stock);
}
return "库存不⾜,该商品已抢购完!";
} catch (Exception e) {
} finally {
redisLock.unlock();
}
return "库存不⾜,该商品已抢购完!";
}
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论