集成Redis
引入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
配置RedisTemplate
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
分布式锁
代码实现
public class RedisSimpleLock implements AutoCloseable {
public static final Logger log = LoggerFactory.getLogger(RedisSimpleLock.class);
public static final String SUFFIX = "~lock";
private final RedisTemplate<String, Object> redisTemplate;
private final String key;
private final long timeout;
private final TimeUnit unit;
private boolean lock;
private boolean autoUnlock;
public RedisSimpleLock(RedisTemplate<String, Object> redisTemplate, String key, long timeout, TimeUnit unit) {
this(redisTemplate, key, timeout, unit, true);
}
public RedisSimpleLock(RedisTemplate<String, Object> redisTemplate, String key, long timeout, TimeUnit unit, boolean autoUnlock) {
this.redisTemplate = redisTemplate;
this.key = key + SUFFIX;
this.timeout = timeout;
this.unit = unit;
this.autoUnlock = autoUnlock;
}
public RedisSimpleLock(RedisTemplate<Object, Object> redisTemplate, String key, long timeout, TimeUnit unit, boolean autoUnlock) {
this.redisTemplate = redisTemplate;
this.key = key + SUFFIX;
this.timeout = timeout;
this.unit = unit;
this.autoUnlock = autoUnlock;
}
public boolean lock() throws Exception {
Boolean res = redisTemplate.opsForValue().setIfAbsent(key, "lock", timeout, unit);
if (res == null) {
log.info("Redis lock key:{},timeout:{},timeUnit:{} ==> Result:[{}]", key, timeout, unit, "error");
throw new Exception();
} else {
log.info("Redis lock key:{},timeout:{},timeUnit:{} ==> Result:[{}]", key, timeout, unit, res);
this.lock = res;
return res;
}
}
private void unlock() {
if (lock) {
try {
Object currentValue = redisTemplate.opsForValue().get(key);
if (currentValue != null) {
redisTemplate.opsForValue().getOperations().delete(key);
log.info("Redis unlock key:{} ==> done.", key);
} else {
log.warn("Redis unlock key:{} ==> Key not exists,skip.", key);
}
} catch (Exception e) {
log.error("Redis unlock key:{} ==> An error has occurred.", key, e);
}
} else {
log.info("Redis unlock key:{} ==> skip.", key);
}
}
@Override
public void close() {
if (autoUnlock) {
unlock();
}
}
}
测试
- 测试代码
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisLockApplicationTests {
public static final Logger log = LoggerFactory.getLogger(RedisLockApplicationTests.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Test
public void contextLoads() {
ExecutorService pool = Executors.newCachedThreadPool(new ThreadFactory() {
final AtomicInteger threadNumber = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "RedisLock-" + threadNumber.getAndIncrement());
}
});
for (int i = 0; i < 10; i++) {
pool.submit(() -> {
try (RedisSimpleLock lock = new RedisSimpleLock(redisTemplate, "TESTLOCK", 30, TimeUnit.SECONDS)) {
if (lock.lock()) {
log.info("获取锁成功,执行业务逻辑");
Thread.sleep(10000);
log.info("业务逻辑执行完毕");
} else {
log.info("未获取到锁");
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
pool.shutdown();
log.info("等待业务完成");
while (!pool.isTerminated()) {
}
log.info("程序结束");
}
}
- 控制台输出
2019-07-16 23:05:15.826 INFO 3779 --- [ RedisLock-2] io.lettuce.core.EpollProvider : Starting without optional epoll library
2019-07-16 23:05:15.830 INFO 3779 --- [ RedisLock-2] io.lettuce.core.KqueueProvider : Starting without optional kqueue library
2019-07-16 23:05:16.136 INFO 3779 --- [ RedisLock-9] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[true]
2019-07-16 23:05:16.136 INFO 3779 --- [ RedisLock-4] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[false]
2019-07-16 23:05:16.136 INFO 3779 --- [ RedisLock-7] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[false]
2019-07-16 23:05:16.136 INFO 3779 --- [ RedisLock-4] c.s.redislock.RedisLockApplicationTests : 未获取到锁
2019-07-16 23:05:16.136 INFO 3779 --- [ RedisLock-7] c.s.redislock.RedisLockApplicationTests : 未获取到锁
2019-07-16 23:05:16.136 INFO 3779 --- [ RedisLock-9] c.s.redislock.RedisLockApplicationTests : 获取锁成功,执行业务逻辑
2019-07-16 23:05:16.137 INFO 3779 --- [ RedisLock-4] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> skip.
2019-07-16 23:05:16.137 INFO 3779 --- [ RedisLock-7] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> skip.
2019-07-16 23:05:16.137 INFO 3779 --- [ RedisLock-6] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[false]
2019-07-16 23:05:16.138 INFO 3779 --- [ RedisLock-6] c.s.redislock.RedisLockApplicationTests : 未获取到锁
2019-07-16 23:05:16.138 INFO 3779 --- [ RedisLock-3] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[false]
2019-07-16 23:05:16.138 INFO 3779 --- [ RedisLock-6] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> skip.
2019-07-16 23:05:16.138 INFO 3779 --- [ RedisLock-3] c.s.redislock.RedisLockApplicationTests : 未获取到锁
2019-07-16 23:05:16.138 INFO 3779 --- [ RedisLock-3] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> skip.
2019-07-16 23:05:16.139 INFO 3779 --- [ RedisLock-1] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[false]
2019-07-16 23:05:16.139 INFO 3779 --- [ RedisLock-1] c.s.redislock.RedisLockApplicationTests : 未获取到锁
2019-07-16 23:05:16.139 INFO 3779 --- [ RedisLock-1] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> skip.
2019-07-16 23:05:16.140 INFO 3779 --- [ RedisLock-10] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[false]
2019-07-16 23:05:16.140 INFO 3779 --- [ RedisLock-5] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[false]
2019-07-16 23:05:16.140 INFO 3779 --- [ RedisLock-10] c.s.redislock.RedisLockApplicationTests : 未获取到锁
2019-07-16 23:05:16.140 INFO 3779 --- [ RedisLock-5] c.s.redislock.RedisLockApplicationTests : 未获取到锁
2019-07-16 23:05:16.140 INFO 3779 --- [ RedisLock-8] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[false]
2019-07-16 23:05:16.140 INFO 3779 --- [ RedisLock-10] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> skip.
2019-07-16 23:05:16.140 INFO 3779 --- [ RedisLock-5] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> skip.
2019-07-16 23:05:16.140 INFO 3779 --- [ RedisLock-8] c.s.redislock.RedisLockApplicationTests : 未获取到锁
2019-07-16 23:05:16.140 INFO 3779 --- [ RedisLock-8] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> skip.
2019-07-16 23:05:16.141 INFO 3779 --- [ RedisLock-2] c.s.redislock.config.RedisSimpleLock : Redis lock key:TESTLOCK~lock,timeout:30,timeUnit:SECONDS ==> Result:[false]
2019-07-16 23:05:16.142 INFO 3779 --- [ RedisLock-2] c.s.redislock.RedisLockApplicationTests : 未获取到锁
2019-07-16 23:05:16.142 INFO 3779 --- [ RedisLock-2] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> skip.
2019-07-16 23:05:26.137 INFO 3779 --- [ RedisLock-9] c.s.redislock.RedisLockApplicationTests : 业务逻辑执行完毕
2019-07-16 23:05:26.145 INFO 3779 --- [ RedisLock-9] c.s.redislock.config.RedisSimpleLock : Redis unlock key:TESTLOCK~lock ==> done.
2019-07-16 23:05:26.146 INFO 3779 --- [ main] c.s.redislock.RedisLockApplicationTests : 程序结束