From ece94554d288b1d63c1cf16e82150df0beb53c16 Mon Sep 17 00:00:00 2001 From: zhangpeng Date: Tue, 28 Feb 2023 18:44:33 +0800 Subject: [PATCH 1/3] =?UTF-8?q?[=E6=96=B0=E5=A2=9E]:redisTemplate=E9=94=81?= =?UTF-8?q?=E7=BB=AD=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executor/RedisTemplateLockExecutor.java | 46 ++++++++++++++++++- .../RedisTemplateLockAutoConfiguration.java | 4 +- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedisTemplateLockExecutor.java b/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedisTemplateLockExecutor.java index 9d70b83..e984ae4 100644 --- a/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedisTemplateLockExecutor.java +++ b/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedisTemplateLockExecutor.java @@ -16,6 +16,8 @@ package com.baomidou.lock.executor; +import com.baomidou.lock.exception.LockFailureException; +import com.baomidou.lock.spring.boot.autoconfigure.Lock4jProperties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.StringRedisTemplate; @@ -23,6 +25,9 @@ import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.RedisScript; import java.util.Collections; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CompletableFuture; /** * 分布式锁原生RedisTemplate处理器 @@ -37,17 +42,41 @@ public class RedisTemplateLockExecutor extends AbstractLockExecutor { "ARGV[1],'NX','PX',ARGV[2])", String.class); private static final RedisScript SCRIPT_UNLOCK = new DefaultRedisScript<>("if redis.call('get',KEYS[1]) " + "== ARGV[1] then return tostring(redis.call('del', KEYS[1])==1) else return 'false' end", String.class); + private static final RedisScript SCRIPT_RENEWAL = new DefaultRedisScript<>("if redis.call('exists', KEYS[1], ARGV[1]) == 1 " + + "then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end", Boolean.class); private static final String LOCK_SUCCESS = "OK"; private final StringRedisTemplate redisTemplate; + private final Lock4jProperties lock4jProperties; + + @Override + public boolean renewal() { + return true; + } @Override public String acquire(String lockKey, String lockValue, long expire, long acquireTimeout) { - String lock = redisTemplate.execute(SCRIPT_LOCK, + + final long newExpire = expire > 0 ? expire : lock4jProperties.getExpire(); + + CompletableFuture cf = CompletableFuture.supplyAsync(() -> redisTemplate.execute(SCRIPT_LOCK, redisTemplate.getStringSerializer(), redisTemplate.getStringSerializer(), Collections.singletonList(lockKey), - lockValue, String.valueOf(expire)); + lockValue, String.valueOf(newExpire))) + .thenApply(acquired -> { + //成功开始续期且传-1时开始续期 + if (LOCK_SUCCESS.equals(acquired)&&expire==-1) { + renewExpiration(newExpire,lockKey,lockValue); + } + return acquired; + }); + String lock; + try { + lock = cf.get(); + } catch (Exception e) { + throw new LockFailureException("锁获取失败!"); + } final boolean locked = LOCK_SUCCESS.equals(lock); return obtainLockInstance(locked, lock); } @@ -61,4 +90,17 @@ public class RedisTemplateLockExecutor extends AbstractLockExecutor { return Boolean.parseBoolean(releaseResult); } + + private void renewExpiration(long expire,String lockKey, String lockValue) { + new Timer().schedule(new TimerTask() { + @Override + public void run() { + if (Boolean.TRUE.equals(redisTemplate.execute(SCRIPT_RENEWAL,Collections.singletonList(lockKey),lockValue, String.valueOf(expire)))) { + renewExpiration(expire,lockKey,lockValue); + } + } + }, expire * 1000 / 3); + } + + } diff --git a/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/spring/boot/autoconfigure/RedisTemplateLockAutoConfiguration.java b/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/spring/boot/autoconfigure/RedisTemplateLockAutoConfiguration.java index 33ea47e..3b341c3 100644 --- a/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/spring/boot/autoconfigure/RedisTemplateLockAutoConfiguration.java +++ b/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/spring/boot/autoconfigure/RedisTemplateLockAutoConfiguration.java @@ -35,7 +35,7 @@ public class RedisTemplateLockAutoConfiguration { @Bean @Order(200) - public RedisTemplateLockExecutor redisTemplateLockExecutor(StringRedisTemplate stringRedisTemplate) { - return new RedisTemplateLockExecutor(stringRedisTemplate); + public RedisTemplateLockExecutor redisTemplateLockExecutor(StringRedisTemplate stringRedisTemplate,Lock4jProperties lock4jProperties) { + return new RedisTemplateLockExecutor(stringRedisTemplate,lock4jProperties); } } \ No newline at end of file -- Gitee From 517ad15d033e750a6b9f4fee5b911c01784cfae0 Mon Sep 17 00:00:00 2001 From: zhangpeng Date: Tue, 28 Feb 2023 22:01:01 +0800 Subject: [PATCH 2/3] =?UTF-8?q?[=E4=BF=AE=E6=94=B9]:lua=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executor/RedisTemplateLockExecutor.java | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedisTemplateLockExecutor.java b/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedisTemplateLockExecutor.java index e984ae4..25a6c52 100644 --- a/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedisTemplateLockExecutor.java +++ b/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedisTemplateLockExecutor.java @@ -16,7 +16,7 @@ package com.baomidou.lock.executor; -import com.baomidou.lock.exception.LockFailureException; +import com.baomidou.lock.exception.LockException; import com.baomidou.lock.spring.boot.autoconfigure.Lock4jProperties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -42,8 +42,8 @@ public class RedisTemplateLockExecutor extends AbstractLockExecutor { "ARGV[1],'NX','PX',ARGV[2])", String.class); private static final RedisScript SCRIPT_UNLOCK = new DefaultRedisScript<>("if redis.call('get',KEYS[1]) " + "== ARGV[1] then return tostring(redis.call('del', KEYS[1])==1) else return 'false' end", String.class); - private static final RedisScript SCRIPT_RENEWAL = new DefaultRedisScript<>("if redis.call('exists', KEYS[1], ARGV[1]) == 1 " + - "then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end", Boolean.class); + private static final RedisScript SCRIPT_RENEWAL = new DefaultRedisScript<>("if redis.call('get', KEYS[1]) ==ARGV[1] " + + "then return redis.call('pexpire', KEYS[1], ARGV[2]) else return 0 end", Boolean.class); private static final String LOCK_SUCCESS = "OK"; private final StringRedisTemplate redisTemplate; @@ -57,25 +57,26 @@ public class RedisTemplateLockExecutor extends AbstractLockExecutor { @Override public String acquire(String lockKey, String lockValue, long expire, long acquireTimeout) { - final long newExpire = expire > 0 ? expire : lock4jProperties.getExpire(); + final long newExpire = expire > 0 ? expire : lock4jProperties.getExpire(); CompletableFuture cf = CompletableFuture.supplyAsync(() -> redisTemplate.execute(SCRIPT_LOCK, - redisTemplate.getStringSerializer(), - redisTemplate.getStringSerializer(), - Collections.singletonList(lockKey), - lockValue, String.valueOf(newExpire))) - .thenApply(acquired -> { - //成功开始续期且传-1时开始续期 - if (LOCK_SUCCESS.equals(acquired)&&expire==-1) { - renewExpiration(newExpire,lockKey,lockValue); - } - return acquired; - }); + redisTemplate.getStringSerializer(), + redisTemplate.getStringSerializer(), + Collections.singletonList(lockKey), + lockValue, String.valueOf(newExpire))) + .thenApply(acquired -> { + //成功且传-1时开始续期 + if (LOCK_SUCCESS.equals(acquired) && expire == -1) { + renewExpiration(newExpire, lockKey, lockValue); + } + return acquired; + }); String lock; try { lock = cf.get(); } catch (Exception e) { - throw new LockFailureException("锁获取失败!"); + log.error("lock error", e); + throw new LockException(); } final boolean locked = LOCK_SUCCESS.equals(lock); return obtainLockInstance(locked, lock); @@ -91,15 +92,15 @@ public class RedisTemplateLockExecutor extends AbstractLockExecutor { } - private void renewExpiration(long expire,String lockKey, String lockValue) { + private void renewExpiration(long expire, String lockKey, String lockValue) { new Timer().schedule(new TimerTask() { @Override public void run() { - if (Boolean.TRUE.equals(redisTemplate.execute(SCRIPT_RENEWAL,Collections.singletonList(lockKey),lockValue, String.valueOf(expire)))) { - renewExpiration(expire,lockKey,lockValue); + if (Boolean.TRUE.equals(redisTemplate.execute(SCRIPT_RENEWAL, Collections.singletonList(lockKey), lockValue, String.valueOf(expire)))) { + renewExpiration(expire, lockKey, lockValue); } } - }, expire * 1000 / 3); + }, expire / 3); } -- Gitee From dea2a203a021fe917c1a9760d75da3c01bc215cb Mon Sep 17 00:00:00 2001 From: zhangpeng Date: Wed, 1 Mar 2023 10:31:03 +0800 Subject: [PATCH 3/3] =?UTF-8?q?[=E6=96=B0=E5=A2=9E]:redisTemplate=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=BB=AD=E6=9C=9F=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lock/test/SpringBootLockTest.java | 19 +++++++++++++++ .../lock/test/service/UserService.java | 2 ++ .../lock/test/service/UserServiceImpl.java | 23 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/lock4j-test/src/main/java/com/baomidou/lock/test/SpringBootLockTest.java b/lock4j-test/src/main/java/com/baomidou/lock/test/SpringBootLockTest.java index 779bdb1..3aaeddc 100644 --- a/lock4j-test/src/main/java/com/baomidou/lock/test/SpringBootLockTest.java +++ b/lock4j-test/src/main/java/com/baomidou/lock/test/SpringBootLockTest.java @@ -171,4 +171,23 @@ public class SpringBootLockTest { Thread.sleep(Long.MAX_VALUE); } + /** + * redisTemplate锁续期 + */ + @SneakyThrows + @Test + public void renewExpirationTemplate(){ + ExecutorService executorService = Executors.newFixedThreadPool(10); + Runnable task = new Runnable() { + @Override + public void run() { + userService.renewExpirationTemplate(); + } + }; + for (int i = 0; i < 1; i++) { + executorService.submit(task); + } + Thread.sleep(Long.MAX_VALUE); + } + } \ No newline at end of file diff --git a/lock4j-test/src/main/java/com/baomidou/lock/test/service/UserService.java b/lock4j-test/src/main/java/com/baomidou/lock/test/service/UserService.java index 59b905e..5b9dbc2 100644 --- a/lock4j-test/src/main/java/com/baomidou/lock/test/service/UserService.java +++ b/lock4j-test/src/main/java/com/baomidou/lock/test/service/UserService.java @@ -39,4 +39,6 @@ public interface UserService { void nonAutoReleaseLock(); + void renewExpirationTemplate(); + } diff --git a/lock4j-test/src/main/java/com/baomidou/lock/test/service/UserServiceImpl.java b/lock4j-test/src/main/java/com/baomidou/lock/test/service/UserServiceImpl.java index e974a48..b819386 100644 --- a/lock4j-test/src/main/java/com/baomidou/lock/test/service/UserServiceImpl.java +++ b/lock4j-test/src/main/java/com/baomidou/lock/test/service/UserServiceImpl.java @@ -19,16 +19,22 @@ package com.baomidou.lock.test.service; import com.baomidou.lock.LockInfo; import com.baomidou.lock.LockTemplate; import com.baomidou.lock.annotation.Lock4j; +import com.baomidou.lock.executor.RedisTemplateLockExecutor; import com.baomidou.lock.executor.RedissonLockExecutor; import com.baomidou.lock.test.model.User; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; +import java.util.concurrent.TimeUnit; + @Service public class UserServiceImpl implements UserService{ @Autowired LockTemplate lockTemplate; + @Autowired + StringRedisTemplate stringRedisTemplate; private int counter = 1; @@ -117,4 +123,21 @@ public class UserServiceImpl implements UserService{ System.out.println("执行nonAutoReleaseLock方法 , 当前线程:" + Thread.currentThread().getName() + " , counter:" + (counter++)); } + @Override + @Lock4j(keys ="1",expire = -1,executor = RedisTemplateLockExecutor.class) + public void renewExpirationTemplate() { + System.out.println("执行renewExpirationTemplate方法 , 当前线程:" + Thread.currentThread().getName() + " , counter:" + (counter++)); + Long expire = stringRedisTemplate.getExpire("lock4j:com.baomidou.lock.test.service.UserServiceImplrenewExpirationTemplate#1", TimeUnit.MILLISECONDS); + System.out.println("获取锁后起始时间:"+expire); + try { + //超过默认过期时间 + Thread.sleep(30000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Long newExpire = stringRedisTemplate.getExpire("lock4j:com.baomidou.lock.test.service.UserServiceImplrenewExpirationTemplate#1",TimeUnit.MILLISECONDS); + System.out.println("处理业务逻辑后续期时间:"+newExpire); + + } + } \ No newline at end of file -- Gitee