在pom.xml中添加依赖:
其中redisson-spring-boot-starter是redisson相关依赖,spring-boot-starter-data-redis是和redis相关的依赖
org.redisson
redisson-spring-boot-starter
3.17.5
org.springframework.boot
spring-boot-starter-data-redis
io.lettuce
lettuce-core
在跟目录下新建一个config包,在config包里面添加一个配置类:RedissonConfig,java
RedissonConfig,java代码:
@Configuration指定该类为配置类,其中@bean声明了一个redissonClient,将其注册到springboot框架中去
这种做法与spring中xml配置取得的效果是一样的,就可以把配置类理解为spring中的xml文件
package com.example.demo.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.redisson.config.TransportMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
config.setTransportMode(TransportMode.NIO);
SingleServerConfig singleServerConfig = config.useSingleServer();
//这一步设置redis的地址
singleServerConfig.setAddress("redis://127.0.0.1:6379");
//设置redis的密码
singleServerConfig.setPassword("123456");
RedissonClient redisson = Redisson.create(config);
return redisson;
}
}
这样就得到一个redissonClient对象了,下面新建一个cotroller包,并建立一个cotroller对象进行实验:
TestController代码:
package com.example.demo.controller;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController
public class TestController {
@Autowired
StringRedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
@GetMapping("read")
public String read(){
RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("lockname");
RLock rLock = readWriteLock.readLock();
try {
rLock.lock();
String uuid = redisTemplate.opsForValue().get("uuid");
return uuid;
}finally {
rLock.unlock();
}
}
@GetMapping("write")
public String write() throws InterruptedException {
RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("lockname");
//写之前加写锁,写锁加锁成功,读锁只能等待
RLock rLock = readWriteLock.writeLock();
String s = "";
try {
rLock.lock();
s = UUID.randomUUID().toString();
Thread.sleep(10000);
redisTemplate.opsForValue().set("uuid",s);
}finally {
rLock.unlock();
}
return s;
}
}
这里AutoWired装填了两个对象:
redisTemplate是redis连接,具体的配置,在application.properties中进行设置,一般springboot建立的时候就已经自动生成了:
redissonClient是配置类里定义的bean
application.yml代码:
spring:
redis:
host: 127.0.0.1
port: 6379
password: "123456"
server:
port: 8080
这里分别设置application.yml中的server.port=8080和8081,同时在两个端口运行springboot:
左上角可以看到开了两个进程:
如果不行的话,可能需要设置一下“允许多个实例”:
在“修改选项”中选择“允许多个实例”
1.读读不互斥:
这里分别访问两个地址的read请求,都能得到结果
、
2.读写互斥:
先访问8080端口的write,再访问8081端口的read,代码里面设置了10秒钟延时模拟写的过程:
所以在write进程在运行时,read是阻塞的,等write进程运行完成,read得到结果
3.写写互斥:
启动两个写请求,后写的请求会等待先写的请求结束后才能写
TestController代码:
package com.example.demo.controller;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController
public class TestController {
@Autowired
StringRedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
@RequestMapping("/buy")
public String deductProduct()
{
RLock redissonLock = redissonClient.getLock("productKey");
redissonLock.lock();
int product = Integer.parseInt(redisTemplate.opsForValue().get("product"));
if(product > 0){
int realProduct = product - 1;
redisTemplate.opsForValue().set("product", realProduct + "");
System.out.println("购买成功,剩余产品数量:" + realProduct);
}
else {
System.out.println("购买失败,库存不足");
}
redissonLock.unlock();
return "end";
}
}
这里需要在redis里面设置一个product变量,表示产品的数量,可以使用redisclient图形化界面进行设置,也可以通过redis命令进行设置:
1.压力测试:
网上下载apache jmeter工具进行压力测试:
(1)thread group:
number of threads:线程请求个数
ramp-up period:在多长时间内将规定的线程请求发送出去
loop count:进行轮数
(2)http:request:
(3)aggressive report:设置日志
2.nginx设置负载均衡:
具体设置是在nginx.conf里面设置,将请求分摊到8080和8081两个端口实现负载均衡:
为什么要设置负载均衡?
因为要模拟高并发的场景,并且分布式锁如果不作用于分布式系统就没有意义
1.这里设置product为100,同时向服务器发送100个购买请求:
可以发现,这里67被设置了两次,说明出现了冲突,因为没有设置锁
test代码中设置了可重入锁,如果不设置锁需要将下面代码删除:
RLock redissonLock = redissonClient.getLock("productKey");
redissonLock.lock();
redissonLock.unlock();
2.设置可重入锁RLock之后就不会出现问题:
设置产品为105件,并在同一时间发送100个并发请求,最后理想是剩下5件产品: