第一步:
<!--引入redis-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.12.0</version>
</dependency>
第二步:config下面创建MyRedissonConfig
package com.atguigu.gulimall.product.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
@Configuration
public class MyRedissonConfig {
@Bean(destroyMethod="shutdown")
public RedissonClient redisson() throws IOException {
//1、创建配置
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.56.10:6379");
//2、根据Config创建出RedissonClient示例
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
第三步:测试
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void teststringRedisTemplate(){
/**
*
*/
//hello world
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
//保存
ops.set("hello","world_"+ UUID.randomUUID().toString());
//查询
String hello = ops.get("hello");
System.out.println("之前保存的数据是:"+hello);
}
进一步分析redisson锁的机制:
引入:
@Autowired RedissonClient redisson; @Autowired StringRedisTemplate redisTemplate;
案例一:
@ResponseBody
@GetMapping("/hello")
public String hello(){
//1、获取一把锁,只要锁的名字一样,就是同一把锁
RLock lock = redisson.getLock("my-lock");
//2、加锁
lock.lock(); //阻塞式等待。默认加的锁都是30s时间。
//1)、锁的自动续期,如果业务超长,运行期间自动给锁续上新的30s。不用担心业务时间长,锁自动过期被删掉
//2)、加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30s以后自动删除。
// lock.lock(10,TimeUnit.SECONDS); //10秒自动解锁,自动解锁时间一定要大于业务的执行时间。
//问题:lock.lock(10,TimeUnit.SECONDS); 在锁时间到了以后,不会自动续期。
//1、如果我们传递了锁的超时时间,就发送给redis执行脚本,进行占锁,默认超时就是我们指定的时间
//2、如果我们未指定锁的超时时间,就使用30 * 1000【LockWatchdogTimeout看门狗的默认时间】;
// 只要占锁成功,就会启动一个定时任务【重新给锁设置过期时间,新的过期时间就是看门狗的默认时间】,每隔10s都会自动再次续期,续成30s
// internalLockLeaseTime【看门狗时间】 / 3,10s
//最佳实战
//1)、lock.lock(30,TimeUnit.SECONDS);省掉了整个续期操作。手动解锁
try{
//Thread.currentThread()是Thread的一个静态方法,用来获取当前线程对象的一个引用。
System.out.println("加锁成功,执行业务..."+Thread.currentThread().getId());
Thread.sleep(30000);
}catch (Exception e){
}finally {
//3、解锁 将设解锁代码没有运行,redisson会不会出现死锁
System.out.println("释放锁..."+Thread.currentThread().getId());//
lock.unlock();
}
return "hello";
}
案例二:
//保证一定能读到最新数据,修改期间,写锁是一个排他锁(互斥锁、独享锁)。读锁是一个共享锁
//写锁没释放读就必须等待
// 读 + 读: 相当于无锁,并发读,只会在redis中记录好,所有当前的读锁。他们都会同时加锁成功
// 写 + 读: 等待写锁释放
// 写 + 写: 阻塞方式
// 读 + 写: 有读锁。写也需要等待。
// 只要有写的存在,都必须等待
@GetMapping("/write")
@ResponseBody
public String writeValue(){
RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
String s = "";
RLock rLock = lock.writeLock();
try {
//1、改数据加写锁,读数据加读锁
rLock.lock();
System.out.println("写锁加锁成功..."+Thread.currentThread().getId());
s = UUID.randomUUID().toString();
Thread.sleep(30000);
redisTemplate.opsForValue().set("writeValue",s);
} catch (Exception e) {
e.printStackTrace();
} finally {
rLock.unlock();
System.out.println("写锁释放"+Thread.currentThread().getId());
}
return s;
}
@GetMapping("/read")
@ResponseBody
public String readValue(){
RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
// ReentrantReadWriteLock writeLock = new ReentrantReadWriteLock();
String s = "";
//加读锁
RLock rLock = lock.readLock();
rLock.lock();
try {
System.out.println("读锁加锁成功"+Thread.currentThread().getId());
s = redisTemplate.opsForValue().get("writeValue");
Thread.sleep(30000);
} catch (Exception e) {
e.printStackTrace();
} finally {
rLock.unlock();
System.out.println("读锁释放"+Thread.currentThread().getId());
}
return s;
}
案例三:
/**
* 车库停车,
* 3车位
* 信号量也可以用作分布式限流;
*/
@GetMapping("/park")
@ResponseBody
public String park() throws InterruptedException {
RSemaphore park = redisson.getSemaphore("park");
// park.acquire();//获取一个信号,获取一个值,占一个车位
boolean b = park.tryAcquire();
if(b){
//执行业务
}else {
return "error";
}
return "ok=>"+b;
}
@GetMapping("/go")
@ResponseBody
public String go() throws InterruptedException {
RSemaphore park = redisson.getSemaphore("park");
park.release();//释放一个车位
//
// Semaphore semaphore = new Semaphore(5);
// semaphore.release();
//
// semaphore.acquire();
return "ok";
}
案例四:
/**
* 放假,锁门
* 1班没人了,2
* 5个班全部走完,我们可以锁大门
*/
@GetMapping("/lockDoor")
@ResponseBody
public String lockDoor() throws InterruptedException {
RCountDownLatch door = redisson.getCountDownLatch("door");
door.trySetCount(5);
door.await(); //等待闭锁都完成
return "放假了...";
}
@GetMapping("/gogogo/{id}")
public String gogogo(@PathVariable("id") Long id){
RCountDownLatch door = redisson.getCountDownLatch("door");
door.countDown();//计数减一;
// CountDownLatch
return id+"班的人都走了...";
}