Java 使用注解实现Redisson分布式锁

简易的使用注解实现Redisson分布式锁

背景

目前的redis分布式锁(RedisLockWrapper),有几个缺点:

  1. 使用复杂。需要引入业务之外的代码。后续更新比较麻烦
  2. 不支持自动续命。
  3. 服务宕机无法快速释放锁。

Redisson分布式锁的有点

  1. Redisson有自旋和超时放弃模式
  2. Redisson有读写锁
  3. Redisson通过自旋不断给锁续命,Redisson订阅了redis消息,业务执行完成阻塞的线程会立马感知到。
  4. Redisson加锁了,但是服务挂掉,即使是强制shutdown,因为锁过期时间非常短,也无需手动删除。如果是计划内关闭,Redisson会在中断执行线程之后删除锁。
  5. Redisson使用lua脚本保证原子性

EasyLock使用方法

  1. 直接在需要加分布式锁的方法添加注解:@EasyLock即可
EasyLock高级使用方法
  1. 默认key:使用【类名+方法名】作为锁名----> @EasyLock
  2. 全参数key:使用【类名+方法名+参数json化之后的MD5】作为锁名。
  3. 单一参数key:使用【类名+方法名+入参属性值】作为锁名-----> @EasyLock(propertyAsKey = "ware.id")
  4. try模式(尝试对应时间去抢占锁,如果抢占失败则返回),0则当场失败/或成功 -----> @EasyLock(waitMillisecond = 5000)
  5. 读写锁模式(读读不互斥,读写互斥,写写互斥)@EasyLock(key = "SpiderV2Controller.ReadWriteLock",mode = RLockModeEnum.READ/RLockModeEnum.WRITE)
    注意:

EasyLock注意事项

  1. 这个和其他的springaop一样,【在bean内调用bean的方法是无法aop的】,所以加的时候要注意
  2. 【静态方法,内部类的方法无法被AOP】,所以也是不支持的

详细使用例子:

com.iceasy.bd.common.redis.example.RedissonExample

复制代码
public class RedissonExample {

    /**
     * 最简易的方式:
     * 1. 分布式锁
     * 2. 使用类名+方法名作为锁名。
     *  如:【REDISSION_LOCK:com.iceasy.bd.common.redis.example.RedissonExample:simpleLock】
     * 3. 未抢到锁的线程会自旋等待,直到
     */
    @EasyLock
    private static void simpleLock(){

    }

    /**
     * 单一参数锁,用于降低锁粒度
     * @param accessToken
     * 1. 使用【类名+方法名+参数值】作为锁名。
     *  比如这里入参的accessToken对象的refreshToken,值为:abcdef,那么锁名如下:
     *  【REDISSION_LOCK:com.iceasy.bd.common.redis.example.RedissonExample:simpleLock:abcdef】
     *
     */
    @EasyLock(propertyAsKey = "accessToken.refreshToken")
    private static void propertyLock(AccessToken accessToken){

    }
    /**
     * 全参数锁
     * @param accessToken
     * 1. 使用【类名+方法名+参数json化之后的MD5】作为锁名。
     *  比如这里入参的accessToken对象,那么会把这个对象转换为json字符串,然后进行MD5,锁名如下:
     *  【REDISSION_LOCK:com.iceasy.bd.common.redis.example.RedissonExample:simpleLock:253f09ee1b2b45ca9430f5695f1372cc】
     *
     */
    @EasyLock(paramAsKey = true)
    private static void paramLock(AccessToken accessToken){

    }

    /**
     * 超时锁
     * 1. 这个锁是利用了redisson的tryLock
     * 2. 如果waitMillisecond为0,就可以快速失败。
     * 3. 如果是大于0的数值,那么就会尝试对应时间去抢占锁,如果抢占失败则返回
     */
    @EasyLock(waitMillisecond = 5000)
    private static void tryLock(){

    }

    /*----------------------------------------------读写锁---------------------------------------------*/
    // 读读不互斥、读写互斥、写写互斥
    // 场景:一个update接口,一个详情接口,如果需要保证强一致,就可以在update接口加上写锁,在列表接口加上读锁。
    /**
     * 读锁
     * 1. 需要和写锁配合,并且key必须一致
     */
    @EasyLock(key = "SpiderV2Controller.ReadWriteLock",mode = RLockModeEnum.READ)
    private static void readLock(){

    }
    /**
     * 写锁
     * 1. 需要和读锁配合,并且key必须一致
     */
    @EasyLock(key = "SpiderV2Controller.ReadWriteLock",mode = RLockModeEnum.WRITE)
    private static void writeLock(){

    }
    /*----------------------------------------------读写锁---------------------------------------------*/

}

总结

可能在嵌套事务会出现释放锁失败,因为spring 可能开启不同的线程执行。

相关推荐
SimonKing1 天前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean1 天前
Jackson View Extension Spring Boot Starter
java·后端
Seven971 天前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
皮皮林5511 天前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河1 天前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
桦说编程1 天前
从 ForkJoinPool 的 Compensate 看并发框架的线程补偿思想
java·后端·源码阅读
躺平大鹅2 天前
Java面向对象入门(类与对象,新手秒懂)
java
初次攀爬者2 天前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺2 天前
搞懂@Autowired 与@Resuorce
java·spring boot·后端