引自免费微信小程序:皆我百晓生
针对您提到的问题,确实存在并发情况下可能的重复提交风险。为了提高并发控制并确保原子性,可以采用Redisson提供的分布式锁机制来解决这个问题。Redisson是一个基于Jedis的高性能Java Redis客户端,它提供了丰富的数据结构和分布式服务,包括分布式锁。
首先,你需要在项目中引入Redisson依赖。如果您使用的是Maven,可以在pom.xml文件中添加以下依赖:
org.redisson
redisson
3.16.7
接下来,我们需要创建一个Redisson客户端,并配置它连接到您的Redis服务器。在Spring Boot应用中,可以创建一个RedissonConfig类:
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Bean
public Config config() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://" + host + ":" + port);
return config;
}
@Bean
public RedissonClient redissonClient(Config config) {
return Redisson.create(config);
}
}
然后,修改isRepeatSubmit方法,利用Redisson的分布式锁来实现线程安全的判断:
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import ...
@Service
public class YourService {
@Autowired
private RedissonClient redissonClient;
...
public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) {
...
// 使用Redisson的分布式锁
RLock lock = redissonClient.getLock(cacheRepeatKey);
try {
// 获取锁,如果获取失败,则表示其他线程正在处理同一请求,返回true
if (!lock.tryLock()) {
return true;
}
// 在这里执行原来的逻辑
Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
if (sessionObj != null) {
...
if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) {
return true;
}
}
...
// 设置缓存并释放锁
redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
lock.unlock();
} catch (Exception e) {
log.error("Error occurred while handling repeat submission", e);
} finally {
// 无论结果如何,都要尝试释放锁
lock.unlock();
}
return false;
}
}
通过这种方式,当多个请求同时到达时,只有一个请求能成功获取到锁并进行后续的检查与缓存操作,其余请求将被阻塞直到锁被释放。这大大降低了并发环境下重复提交的风险。
注意:这个解决方案依赖于Spring框架和Redisson库。如果你的项目中没有使用Spring,那么你需要自行管理Redisson客户端的生命周期,以及使用对应的Java API来替代Spring提供的便利功能。
