Redis分布式锁的工具类

本文介绍了一个SpringBoot中的抽象类,用于在单应用集群中处理并发定时任务,通过Redis实现分布式锁,确保数据一致性。方法`lockAndForeach`遍历集合并对每个对象执行`processObj`方法,处理异常并自动释放锁。
摘要由CSDN通过智能技术生成

背景:因为最近应用压力过大,准备改造成单应用的集群。所以定时任务可能会同时对缓存中的数据进行处理,所以需要增加一个锁的方法。这里我将外部循环抽取成公共部分,单个业务处理需要自行集成实现 processObj 方法逻辑。Redis的加解锁方法自行实现。


import com.sun.istack.internal.NotNull;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;

public abstract class AbstractCtgRedisLock<T>{

    /**
     * 添加分布式锁遍历集合 collection, 外部处理循环异常,具体 业务处理实现 processObj 方法
     * 外部循环不做异常处理,仅释放锁,请外部自行处理异常情况
     *
     * @param collection 需要遍历的集合 例如:[{"id":1,"name":"Jack"},{"id":2,"name":"Tony"},{"id":3,"name":"Lisa"}]
     * @param prefixKey 分布式锁前缀,XXXX_%s格式,内部通过String.format格式化,当此字段为空时,直接使用 field 字段对应的值 加锁 例如:“LOCK_PERSON_%s”
     * @param function 属性获取函数 例如:Class::getId
     * @param expireSeconds 过期时间,秒 例如:60
     * @return 返回成功处理集合的field属性对应的值 例如:成功处理了Jack和Lisa,返回[{1},{3}]
     */
    public List<String> lockAndForeach(@NotNull Collection<T> collection, String prefixKey, Function<T, String> function, int expireSeconds){
        CtgRedis ctgRedis = CtgUtils.getCtgRedis();
        List<String> res = new ArrayList<>();

        for (T t : collection) {
            // 调用该属性的get方法获取属性的值
            String fieldFormat = function.apply(t);
            String result = doLoop(prefixKey, expireSeconds, ctgRedis, t, fieldFormat);
            // 处理结果添加
            if(StringUtils.hasText(result)){
                res.add(result);
            }
        }
        return res;
    }

    /**
     * 添加分布式锁遍历集合 collection, 外部处理循环异常,具体 业务处理实现 processObj 方法
     * 外部循环不做异常处理,仅释放锁,请外部自行处理异常情况
     *
     * @param collection 需要遍历的集合 字符串集合
     * @param prefixKey 分布式锁前缀,XXXX_%s格式,内部通过String.format格式化,当此字段为空时,直接使用 field 字段对应的值 加锁 例如:“LOCK_PERSON_%s”
     * @param expireSeconds 过期时间,秒 例如:60
     * @return 返回成功处理集合的field属性对应的值 例如:成功处理了Jack和Lisa,返回[{1},{3}]
     */
    public List<String> lockAndForeach(@NotNull Collection<T> collection, String prefixKey, int expireSeconds){
        CtgRedis ctgRedis = CtgUtils.getCtgRedis();
        List<String> res = new ArrayList<>();
        for (T t : collection) {

            String result = doLoop(prefixKey, expireSeconds, ctgRedis, t, t.toString());

            if(StringUtils.hasText(result)){
                res.add(result);
            }
        }
        return res;
    }



    private String doLoop(String prefixKey, int expireSeconds, CtgRedis ctgRedis, T t, String fieldFormat) {
        String lockKey;
        if(StringUtils.hasText(prefixKey)){
            lockKey = String.format(prefixKey, fieldFormat);
        }else{
            // 没有format前缀时,直接使用属性值
            lockKey = fieldFormat;
        }
        try{
            if (ctgRedis.lock(lockKey, expireSeconds)) {
                // 实际单个业务处理方法
                processObj(t);
                return fieldFormat;
            }
        } finally{
            ctgRedis.releaseLock(lockKey);
        }
        return null;
    }

    /**
     * 注意处理异常,否则会导致结合遍历中断
     *
     * @param obj 泛型入参
     */
    protected abstract void processObj(T obj);

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值