利用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 >
<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..."); } }