• 基于 Redis + Lua 脚本实现分布式锁,确保操作的原子性


    1.加锁的Lua脚本: lock.lua
    1. --- -1 failed
    2. --- 1 success
    3. --- getLock key
    4. local result = redis.call('setnx' , KEYS[1] , ARGV[1])
    5. if result == 1 then
    6. --PEXPIRE:以毫秒的形式指定过期时间
    7. redis.call('pexpire' , KEYS[1] , 3600000)
    8. else
    9. result = -1;
    10. -- 如果value相同,则认为是同一个线程的请求,则认为重入锁
    11. local value = redis.call('get' , KEYS[1])
    12. if (value == ARGV[1]) then
    13. result = 1;
    14. redis.call('pexpire' , KEYS[1] , 3600000)
    15. end
    16. end
    17. -- 如果获取锁成功,则返回 1
    18. return result
    2.解锁的Lua脚本: unLock.lua
    1. if redis.call('get', KEYS[1]) == ARGV[1]
    2. then
    3. return redis.call('del', KEYS[1])
    4. else
    5. return 0
    6. end
    3.将资源文件放在资源文件夹下

    4.Java中调用lua脚本

    1)获取文件方式

    1. import lombok.extern.slf4j.Slf4j;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.core.io.ClassPathResource;
    4. import org.springframework.data.redis.core.RedisTemplate;
    5. import org.springframework.data.redis.core.script.DefaultRedisScript;
    6. import org.springframework.scripting.support.ResourceScriptSource;
    7. import org.springframework.web.bind.annotation.GetMapping;
    8. import org.springframework.web.bind.annotation.RestController;
    9. import java.util.Arrays;
    10. /**
    11. * @Author: best_liu
    12. * @Description:
    13. * @Date Create in 14:04 2023/10/26
    14. * @Modified By:
    15. */
    16. @Slf4j
    17. @RestController
    18. public class LuaLock {
    19. @Autowired
    20. private RedisTemplate redisTemplate;
    21. @GetMapping(value = "/getLock")
    22. public Long getLock() {
    23. DefaultRedisScript script = new DefaultRedisScript();
    24. script.setResultType(Long.class);
    25. // 获取lua文件方式
    26. script.setScriptSource(new ResourceScriptSource(new ClassPathResource("script/lock.lua")));
    27. Long execute = (Long) redisTemplate.execute(script, Arrays.asList("best_liu"),"best_liu20231026150600");
    28. return execute;
    29. }
    30. }

    2)lua字符串方式

    1. import lombok.extern.slf4j.Slf4j;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.data.redis.core.RedisTemplate;
    4. import org.springframework.data.redis.core.script.DefaultRedisScript;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import org.springframework.web.bind.annotation.RestController;
    7. import java.util.Arrays;
    8. /**
    9. * @Author: best_liu
    10. * @Description:
    11. * @Date Create in 14:04 2023/10/26
    12. * @Modified By:
    13. */
    14. @Slf4j
    15. @RestController
    16. public class LuaLock {
    17. @Autowired
    18. private RedisTemplate redisTemplate;
    19. @GetMapping(value = "/getLock")
    20. public Long getLock() {
    21. DefaultRedisScript script = new DefaultRedisScript();
    22. script.setResultType(Long.class);
    23. // 获取lua文件方式
    24. // script.setScriptSource(new ResourceScriptSource(new ClassPathResource("script/lock.lua")));
    25. String lua = "local result = redis.call('setnx' , KEYS[1] , ARGV[1])\n" +
    26. "if result == 1 then\n" +
    27. " redis.call('pexpire' , KEYS[1] , 3600000)\n" +
    28. "else\n" +
    29. " result = -1;\n" +
    30. " local value = redis.call('get' , KEYS[1])\n" +
    31. " if (value == ARGV[1]) then\n" +
    32. " result = 1;\n" +
    33. " redis.call('pexpire' , KEYS[1] , 3600000)\n" +
    34. " end\n" +
    35. "end\n" +
    36. "return result";
    37. script.setScriptText(lua);
    38. Long execute = (Long) redisTemplate.execute(script, Arrays.asList("best_liu"),"best_liu20231026150600");
    39. return execute;
    40. }
    41. }
    5.jedis调用Lua脚本实现分布式重试锁

    1)引入jedis依赖

    1. redis.clients
    2. jedis
    3. 2.9.0

    2)jedis调用lua

    1. import lombok.extern.slf4j.Slf4j;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.web.bind.annotation.GetMapping;
    4. import org.springframework.web.bind.annotation.RestController;
    5. import redis.clients.jedis.Jedis;
    6. import java.util.ArrayList;
    7. import java.util.Arrays;
    8. import java.util.List;
    9. @Slf4j
    10. @RestController
    11. public class LuaLock {
    12. @GetMapping(value = "/getLock")
    13. public Long getLock() {
    14. //获取连接
    15. Jedis jedis = new Jedis("127.0.0.1", 6379);
    16. String lua = "local result = redis.call('setnx' , KEYS[1] , ARGV[1])\n" +
    17. "if result == 1 then\n" +
    18. " redis.call('pexpire' , KEYS[1] , ARGV[2])\n" +
    19. "else\n" +
    20. " result = -1;\n" +
    21. " local value = redis.call('get' , KEYS[1])\n" +
    22. " if (value == ARGV[1]) then\n" +
    23. " result = 1;\n" +
    24. " redis.call('pexpire' , KEYS[1] , ARGV[2])\n" +
    25. " end\n" +
    26. "end\n" +
    27. "return result";
    28. List keys = new ArrayList<>();
    29. List values = new ArrayList<>();
    30. keys.add("best_liu");
    31. values.add("best_liu20231026150600");
    32. values.add("3600000");
    33. Object result = jedis.eval(lua, keys, values);
    34. System.out.println(result);
    35. return 1L;
    36. }
    37. }

  • 相关阅读:
    详解vue3的ref和reactive
    R语言survival包的survfit函数拟合生存曲线数据、survminer包的ggcompetingrisks函数可视化竞争风险累积事件曲线
    web前端-JavaScript中的forEach和map方法
    C语言百日刷题第八天
    java计算机毕业设计ssm建设路小学读背兴趣任务管理系统
    【牛客-剑指offer-数据结构篇】JZ52 两个链表的第一个公共节点 两种思路 Java实现
    如何备份和恢复数据库
    Hive数据定义语言-DDL-建表高阶语法(内外部、分区、分桶、事务、视图、物化视图)
    力扣每日一题:1752. 检查数组是否经排序和轮转得到
    使用python玩转二维码!速学速用!⛵
  • 原文地址:https://blog.csdn.net/askuld/article/details/134059575