springboot 集成redission 以及分布式锁的使用详解

网友投稿 802 2022-09-21


springboot 集成redission 以及分布式锁的使用详解

目录springboot集成redission及分布式锁的使用1、引入jar包2、增加Configuration类3、使用redission分布式锁Springboot整合Redisson 锁一、依赖二、配置文件三、锁的使用四、分布式秒杀五、redis锁 单机版可用,分布式用Redisson

springboot集成redission及分布式锁的使用

1、引入jar包http://

org.redisson

redisson

3.13.4

2、增加Configuration类

@Configuration

public class RedissonConfig {

@Value("${spring.redis.host}")

private String host;

@Value("${spring.redis.port}")

private String port;

@Value("${spring.redis.password}")

private String password;

@Bean

public RedissonClient getRedisson() {

Config config = new Config();

config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password);

return Redisson.create(config);

}

}

3、使用redission分布式锁

@Autowired

private RedissonClient redissonClient;

//方法区

String key = "aa:bb:cc:01";

RLock rLock =redissonClient.getLock(key);

try{
// 尝试加锁,最多等待1秒,上锁以后10秒自动解锁
// 没有Watch Dog ,10s后自动释放

boolean res = rLock.tryLock(1,10, TimeUnit.SECONDS);

if(!res){

  return new GeneralVO<>(400, "请勿重复提交", false);

}

}finally{

rLock.unlock();

}

private void redissonDoc() throws InterruptedException {

//1. 普通的可重入锁

RLock lock = redissonClient.getLock("generalLock");

// 拿锁失败时会不停的重试

// 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s

lock.lock();

// 尝试拿锁10s后停止重试,返回false

// 具有Watch Dog 自动延期机制 默认续30s

boolean res1 = lock.tryLock(10, TimeUnit.SECONDS);

// 拿锁失败时会不停的重试

// 没有Watch Dog ,10s后自动释放

lock.lock(10, TimeUnit.SECONDS);

// 尝试拿锁100s后停止重试,返回false

// 没有Watch Dog ,10s后自动释放

boolean res2 = lock.tryLock(100, 10, TimeUnit.SECONDS);

//2. 公平锁 保证 Redisson 客户端线程将以其请求的顺序获得锁

RLock fairLock = redissonClient.getFairLock("fairLock");

//3. 读写锁 没错与JDK中ReentrantLock的读写锁效果一样

RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("readWriteLock");

readWriteLock.readLock().lock();

readWriteLock.writeLock().lock();

}

Springboot整合Redisson 锁

Redisson是一个在Redis的基础上实现的java驻内存数据网格

一、依赖

org.redisson

redisson

3.15.4

二、配置文件

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("${spring.redis.host}")

private String host;

@Value("${spring.redis.port}")

private int port;

@Value("${spring.redis.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);

return Redisson.create(config);

}

}

三、锁的使用

读写锁

public class RedissionDemo {

@Autowired

private RedissonClient redissonClient;

@Autowired

private RedisTemplate redisTemplate;

/**

* 读写锁 总结

*

* 读锁又叫共享锁

* 写锁又叫排他锁(互斥锁)

* 读 + 读 相当于无锁,并发读,同时加锁成功

* 写 + 写 阻塞状态

* 写 + 读 等待写锁释放

* 读 + 写 等待http://读锁完,才写,

*/

public String writeValue() {

String str = "";

RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("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 = redissonClient.getReadWriteLock("writeLock");

RLock rLock = readWriteLock.readLock();

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 = redissonClient.getSemaphore("park");

//这里会将信号量里面的值-1,如果为0则一直等待,直到信号量>0

park.acquire();

//tryAcquire为非阻塞式等待

//park.tryAcquire();

return "ok";

}

public String go() throws InterruptedException {

//这里是获取信号量的值,这个信号量的name一定要与你初始化的一致

RSemaphore park = redissonClient.getSemaphore("park");

//这里会将信号量里面的值+1,也就是释放信号量

park.release();

return "ok";

}

}

闭锁

public class RedissionDemo {

@Autowired

private RedissonClient redissonClient;

@Autowired

private RedisTemplate redisTemplate;

/**

* 闭锁,限流

*

* @return

* @throws InterruptedException

*/

//锁门

public String lockdoor() throws InterruptedException {

RCountDownLatch door = redissonClient.getCountDownLatch("door");

//设置一个班级有20个同学

door.trySetCount(20);

//需要等到20个同学全部离开,才锁门

door.await();

return "锁门了";

}

public String leave(Long id) throws InterruptedException {

RCountDownLatch door = redissonClient.getCountDownLatch("door");

//表示一个同学离开

door.countDown();

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";

redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(goodsId), lock);

}

}

return doKill();

}

/**

* 整合 redission

* @return

*/

public String doKillDistributed() {

String goodsId = "10054";

RLock lock = redissonClient.getLock(upActivityKey() + SecKillConstant.LOCK + goodsId);

// 获取锁成功

try {

//1 阻塞式等待,默认30秒时间

//2 自动续期,如果业务超长,续上新的30秒,不用担心过期时间,锁自动删除掉

//3 枷锁的业务运行完成,就不会给当前的锁自动续期,即使没有手动释放锁也会,30秒自动释放

// lock.lock(30, TimeUnit.SECONDS); //不会自动续期需要注意

lock.lock();

Long stock = redisWIRfPrhTemplate.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.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.core.script.DefaultRedisScript;

import org.springframework.stereotype.Service;

import java.util.Collections;

import java.util.UUID;

import java.util.concurrent.TimeUnit;

/**

* redis 锁 集群有瑕疵 不能 续命

*/

@Service

public class RedisLock {

@Autowired

private RedisTemplate redisTemplate;

private String lockName = "lockName";

private ThreadLocal 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";

redisTemplate.execute(new DefaultRedisScript(script, Long.class), CollectioWIRfPrhns.singletonList(lockName), threadLocal.get());

}

}

使用

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 "库存不足,该商品已抢购完!";

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:BGP十三条选路---实验(上)
下一篇:CCNP(ISCW)实验:配置GRE隧道(2.1)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~