利用redis实现分布式锁

一、背景

  在分布式项目中,由于一个服务会有多个实例运行,有些特定的场景需要我们用到分布式锁。

  例如:最近我正在做的交易所项目,其中一个服务是钱包模块,需要每半个小时就去归集用户的资金,这个定时任务只能有一个实例执行,要不然就会导致数据错乱。

二、解决方案

  针对这种场景,利用redis来实现并发控制是一个不错的选择。

  1.添加jedis 的 maven依赖

       <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.2</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>

  2.添加bean文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
    <bean id="redisService" class="com.w3liu.redis.RedisService" init-method="init">
        <property name="host">
            <value>127.0.0.1</value>
        </property>
        <property name="password">
            <value>123456</value>
        </property>
        <property name="port">
            <value>23671</value>
        </property>
        <property name="maxIdle">
            <value>500</value>
        </property>
        <property name="maxTotal">
            <value>4000</value>
        </property>
    </bean>
</beans>

  2.封装核心方法

@Slf4j
public class RedisService {

    public String host;

    public String port;

    public String password;

    private String maxIdle;

    private String maxTotal;

    private JedisPool pool;

    public void init() {

        int iMaxIdle = Integer.parseInt(maxIdle);
        int iMaxTotal = Integer.parseInt(maxTotal);
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxIdle(iMaxIdle);
        config.setMaxTotal(iMaxTotal);
        config.setTestOnBorrow(false);
        config.setTestOnReturn(false);
        pool = new JedisPool(config, host, Integer.parseInt(port), 3000, password);

    }

    /**
     * 原子设置一个具有自定义过期时间的值
     *
     * @param key
     * @param value
     * @return
     */
    public boolean setnx(String key, String value, int time) {
        boolean b = false;
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            String re = jedis.set(key, value, "nx", "px", time);
            if (StringUtils.isNotBlank(re))
                b = "OK".equals(re);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return b;
    }
}

  3.调用

@Scheduled(cron = "0 0/30 * * * ?")
    public void doTask() {
        String lockKey = "LOCK_FLAG";
        String uuid = UUID.randomUUID().toString();
        if (redisService.setnx(lockKey, uuid, 10 * 60 * 1000)) {
            log.info("do some thing...");
        }
    }

  

原文地址:https://www.cnblogs.com/w3liu/p/10068362.html