赞
踩
- @GetMapping("/testJmeter")
- public void testJmeter() {
-
- synchronized (this){
- int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"))
- if (stock > 0) {
- int realStock = stock - 1;
- stringRedisTemplate.opsForValue().set("stock",realStock);
- System.out.println("扣减成功,剩余:"+ realStock);
- } else {
- System.out.println("扣减失败");
- }
- }
- }
问题:上面这种方法在单台Tomcat 服务中,可以实现 防止超卖问题,可是在实际项目开发中,我们部署项目一般不会只使用一台服务器 部署,一般都是多台服务器 通过 Nginx 实现服务代理,负载均衡。 这样简单使用 synchronized 是不可取的!!!
- @GetMapping("/testJmeter")
- public void testJmeter() {
- try {
- String lockKey = "lockKey";
- Boolean result = stringRedisTempalte.opsForValue.setIfAbsent(lockKey,"zhuzhe");
- if (!result) {
- return "错误";
- }
- int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"))
- if (stock > 0) {
- int realStock = stock - 1;
- stringRedisTemplate.opsForValue().set("stock",realStock);
- System.out.println("扣减成功,剩余:"+ realStock);
- } else {
- System.out.println("扣减失败");
- }
- } finaly{
- stringRedisTempalte.delete(lockKey);
- }
- }
问题:但是上述容易出现,某台机器突然宕机的现象,就无法走到finally 中去释放锁了。导师redis 中 的锁还没有释放。别的机器就无法获得锁了。 就会出现死锁问题。
可以实现对 给这把锁加上一个过期时间
- @GetMapping("/testJmeter")
- public void testJmeter() {
- try {
- String lockKey = "lockKey";
- Boolean result = stringRedisTempalte.opsForValue
- .setIfAbsent(lockKey,"zhuzhe",10,TimeUnit.SECONDS); // 设置过期时间
- if (!result) {
- return "错误";
- }
- int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"))
- if (stock > 0) {
- int realStock = stock - 1;
- stringRedisTemplate.opsForValue().set("stock",realStock);
- System.out.println("扣减成功,剩余:"+ realStock);
- } else {
- System.out.println("扣减失败");
- }} finaly{
- stringRedisTempalte.delete(lockKey);
- }
- }
依然会有点问题--->失效时间不好设置,其中业务逻辑出现 SQL 慢查询导致代码执行时间长,在高并发情况下,会出现删 错锁的情况。A服务把 B服务中的锁 删除了。
每个线程都生成一个唯一id
- @GetMapping("/testJmeter")
- public void testJmeter() {
- try {
- String lockKey = "lockKey";
- String clientId = UUID.randomUUID.totring();
-
- Boolean result = stringRedisTempalte.opsForValue
- .setIfAbsent(lockKey ,clientId ,10,TimeUnit.SECONDS); // 设置过期时间
- if (!result) {
- return "错误";
- }
- int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"))
- if (stock > 0) {
- int realStock = stock - 1;
- stringRedisTemplate.opsForValue().set("stock",realStock);
- System.out.println("扣减成功,剩余:"+ realStock);
- } else {
- System.out.println("扣减失败");
- }} finaly{
- if (clientId.equals(stringRedisTempalte.opsForValue.getLockKey)){
- stringRedisTempalte.delete(lockKey);
- }
-
- }
- }
注意:其实还可以使用,创建一个定时任务,每10s 检查这个主线程的锁是否过期,如果快过期了,任务还没有结束,在延长30s.
引入 Redission 依赖
- <dependency>
- <groupId>org.redisson</groupId>
- <artifactId>redisson</artifactId>
- <version>3.6.5</version>
- </dependency>
配置:
- @Configuration
- public class RedissonConfig {
-
- @Value("${spring.redis.host}")
- private String address;
- @Value("${spring.redis.port}")
- private String port;
- @Value("${spring.redis.password}")
- private String password;
-
- @Bean
- public RedissonClient redissonClient() {
- Config config = new Config();
- //此处为单机模式 (注:有多种模式)
- config.useSingleServer()
- .setAddress("redis://" + address + ":"+port)
- .setPassword(password)
- .setTimeout(10000)
- .setRetryAttempts(5)
- .setRetryInterval(2000)
- .setConnectionPoolSize(64)
- .setConnectionMinimumIdleSize(24)
- // 保持连接活动
- .setKeepAlive(true)
- // 发送PING命令的间隔时间;
- .setPingConnectionInterval(30000);
-
- return Redisson.create(config);
- }
- }
代码示例:
- @Rescourse
- private Redisson redisson;
-
- @GetMapping("/testJmeter")
- public void testJmeter() {
- try {
- String lockKey = "lockKey";
- String clientId = UUID.randomUUID.totring();
-
- //获取锁
- Rlock redissonLock = redisson.getLock(lockkey);
-
-
- //Boolean result = stringRedisTempalte.opsForValue
- .setIfAbsent(lockKey ,clientId ,10,TimeUnit.SECONDS); // 设置过期时间
- //if (!result) {
- // return "错误";
- // }
- //加锁
- redissonLock.lock()
-
- int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"))
- if (stock > 0) {
- int realStock = stock - 1;
- stringRedisTemplate.opsForValue().set("stock",realStock);
- System.out.println("扣减成功,剩余:"+ realStock);
- } else {
- System.out.println("扣减失败");
- }} finaly{
- //释放锁
- redissonLock.unlock()
- // if (clientId.equals(stringRedisTempalte.opsForValue.getLockKey)){
-
-
- //stringRedisTempalte.delete(lockKey);
- }
-
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。