完成分布式锁的三种方式

第一种使用lua脚本完成分布式锁

package com.atguigu.bootredis01.controller;

import com.atguigu.bootredis01.util.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author 蒲成伟
 * @create 2021-08-30-13:49
 */

@RestController
public class GoodConreoller {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Value("${server.port}")
    private String serverPort;

    private static final String REDIS_LOCK = "atguigu";

    @GetMapping("/buy_goods")
    public String buy_Goods() throws Exception {

        long start = System.currentTimeMillis();
        String value = UUID.randomUUID().toString() + Thread.currentThread().getName();
        try {

            Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK, value, 10L, TimeUnit.SECONDS);
            if(!flag){
                System.out.println("枪锁失败");
                return "枪锁失败";
            }
            String result = stringRedisTemplate.opsForValue().get("goods:001");
            int goodsNumber = result==null ? 0:Integer.parseInt(result);
            if(goodsNumber > 0){
                int realNUmber = goodsNumber - 1;
                stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNUmber));
                System.out.println("成功买到商品,还剩下:"+realNUmber+"件库存"+"服务提供者是:"+serverPort);
                return  Thread.currentThread().getName()+"来光顾"+"成功买到商品,还剩下:"+realNUmber+"件库存"+"服务提供者是:"+serverPort;
            }else {
                System.out.println(Thread.currentThread().getName()+"来光顾 "+"卖完了啊,下次早点来啊"+"服务提供者是:"+serverPort);
            }
            return  "卖完了啊,下次早点来啊"+"服务提供者是:"+serverPort;
        } finally {
            //不满足原子性,不能这么写
//            if( stringRedisTemplate.opsForValue().get(REDIS_LOCK).equalsIgnoreCase(value)){
//                stringRedisTemplate.delete(REDIS_LOCK);
//            }
            //使用redis事务
//            while(true)
//            {
//                stringRedisTemplate.watch(REDIS_LOCK);
//                if(stringRedisTemplate.opsForValue().get(REDIS_LOCK).equalsIgnoreCase(value)){
//                    stringRedisTemplate.setEnableTransactionSupport(true);
//                    stringRedisTemplate.multi();
//                    stringRedisTemplate.delete(REDIS_LOCK);
//                    List<Object> list = stringRedisTemplate.exec();
//                    if (list == null)
//                        continue;
//
//                }
//                stringRedisTemplate.unwatch();
//                break;
//
//            }
            //使用正常的写法
            Jedis jedis = RedisUtils.getJedis();
            String script ="if redis.call('get',KEYS[1]) == ARGV[1] " +
                    "then " +
                    "return redis.call('del',KEYS[1]) " +
                    "else " +
                    "    return 0 " +
                    "end";
            try {
                Object eval = jedis.eval(script, Collections.singletonList(REDIS_LOCK), Collections.singletonList(value));
                if("1".equalsIgnoreCase(eval.toString())){
                    System.out.println("-------del redis lock ok");
                }
                else {
                    System.out.println("-------del redis lock error");
                }
            }finally {
                if(null != jedis){
                    jedis.close();
                    long finish = System.currentTimeMillis();

                    long timeElapsed = finish - start;
                    System.out.println("耗费时间 " + timeElapsed);
                }
            }
        }


    }
}

第二种:使用redis事务完成分布式事务锁

package com.atguigu.bootredis01.controller;

import com.atguigu.bootredis01.util.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author 蒲成伟
 * @create 2021-08-30-13:49
 */

@RestController
public class GoodConreoller {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Value("${server.port}")
    private String serverPort;

    private static final String REDIS_LOCK = "atguigu";

    @GetMapping("/buy_goods")
    public String buy_Goods() throws Exception {
        String value = UUID.randomUUID().toString() + Thread.currentThread().getName();
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK, value, 10L, TimeUnit.SECONDS);
        if(!flag){
            System.out.println("枪锁失败");
            return "枪锁失败";
        }
        try {
            String result = stringRedisTemplate.opsForValue().get("goods:001");
            int goodsNumber = result==null ? 0:Integer.parseInt(result);
            if(goodsNumber > 0){
                int realNUmber = goodsNumber - 1;
                stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNUmber));
                System.out.println("成功买到商品,还剩下:"+realNUmber+"件库存"+"服务提供者是:"+serverPort);
                return  Thread.currentThread().getName()+"来光顾"+"成功买到商品,还剩下:"+realNUmber+"件库存"+"服务提供者是:"+serverPort;
            }else {
                System.out.println(Thread.currentThread().getName()+"来光顾 "+"卖完了啊,下次早点来啊"+"服务提供者是:"+serverPort);
            }
            return  "卖完了啊,下次早点来啊"+"服务提供者是:"+serverPort;
        } finally {
            //不满足原子性,不能这么写
//            if( stringRedisTemplate.opsForValue().get(REDIS_LOCK).equalsIgnoreCase(value)){
//                stringRedisTemplate.delete(REDIS_LOCK);
//            }
            //使用redis事务
//            while(true)
//            {
//                stringRedisTemplate.watch(REDIS_LOCK);
//                if(stringRedisTemplate.opsForValue().get(REDIS_LOCK).equalsIgnoreCase(value)){
//                    stringRedisTemplate.setEnableTransactionSupport(true);
//                    stringRedisTemplate.multi();
//                    stringRedisTemplate.delete(REDIS_LOCK);
//                    List<Object> list = stringRedisTemplate.exec();
//                    if (list == null)
//                        continue;
//
//                }
//                stringRedisTemplate.unwatch();
//                break;
//
//            }
            //使用正常的写法
            Jedis jedis = RedisUtils.getJedis();
            String script ="if redis.call('get',KEYS[1]) == ARGV[1] " +
                    "then " +
                    "return redis.call('del',KEYS[1]) " +
                    "else " +
                    "    return 0 " +
                    "end";
            try {
                Object eval = jedis.eval(script, Collections.singletonList(REDIS_LOCK), Collections.singletonList(value));
                if("1".equalsIgnoreCase(eval.toString())){
                    System.out.println("-------del redis lock ok");
                }
                else {
                    System.out.println("-------del redis lock error");
                }
            }finally {
                if(null != jedis){
                    jedis.close();
                }
            }
        }


    }
}



第三种:使用redisson加锁

    @Bean
    public Redisson getRedissonInstance(){
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379").setDatabase(0);
        return (Redisson) Redisson.create(config);
    }












package com.atguigu.bootredis01.controller;

import com.atguigu.bootredis01.util.RedisUtils;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author 蒲成伟
 * @create 2021-08-30-13:49
 */

@RestController
public class GoodConreoller {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Value("${server.port}")
    private String serverPort;

    private static final String REDIS_LOCK = "atguigu";

    @Autowired
    private Redisson redisson;

    @GetMapping("/buy_goods")
    public String buy_Goods() throws Exception {
        RLock redissonLock = redisson.getLock(REDIS_LOCK);
        redissonLock.lock();

        try {
            String result = stringRedisTemplate.opsForValue().get("goods:001");
            int goodsNumber = result==null ? 0:Integer.parseInt(result);
            if(goodsNumber > 0){
                int realNUmber = goodsNumber - 1;
                stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNUmber));
                System.out.println("成功买到商品,还剩下:"+realNUmber+"件库存"+"服务提供者是:"+serverPort);
                return  Thread.currentThread().getName()+"来光顾"+"成功买到商品,还剩下:"+realNUmber+"件库存"+"服务提供者是:"+serverPort;
            }else {
                System.out.println(Thread.currentThread().getName()+"来光顾 "+"卖完了啊,下次早点来啊"+"服务提供者是:"+serverPort);
            }
            return  "卖完了啊,下次早点来啊"+"服务提供者是:"+serverPort;
        } finally {
            if (redissonLock.isLocked() && redissonLock.isHeldByCurrentThread())
            {
                redissonLock.unlock();
            }
        }


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值