大数跨境
0
0

在Spring中如何使用Redis乐观锁机制?

在Spring中如何使用Redis乐观锁机制? Spring全家桶实战案例
2024-02-14
0
导读:基于Redis乐观锁的实现

环境:SpringBoot2.7.16 + Redis6.2.10



1. 简介

Redis乐观锁是一种并发控制的方法,它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。

Redis乐观锁不是通过检测版本号来实现的,而是在执行完一个写命令后,会进行检查,检查是否是被WATCH监视的键。

开启事务后,可以执行命令入队,然后执行事务。如果在事务执行期间,被WATCH监视的键发生变化,那么事务会执行失败。

2. Redis客户端演示

WATCH

127.0.0.1:6379> help watchWATCH key [key ...]summary: 观察给定的键以确定MULTI/EXEC块的执行since: 2.2.0group: transactions

MULTI命令

127.0.0.1:6379> help multiMULTI -summary: 标记事务块的开始since: 1.2.0group: transactions

MULTI命令执行之后,后续所有的命令操作不会立即执行,会将这些命令放入到队列中。最后通过后面的EXEC或DISCARD命令提交事务或放弃当前所有的操作。

EXEC命令

127.0.0.1:6379help execsummary: 执行MULTI之后发出的所有命令since: 1.2.0group: transactions

DISCARD命令

127.0.0.1:6379help discardsummary: 放弃MULTI之后发出的所有命令since: 2.0.0group: transactions

MULTI / EXEC / DISCARD演示

127.0.0.1:6379> MULTIOK127.0.0.1:6379(TX)> SET a 1QUEUED127.0.0.1:6379(TX)> INCR aQUEUED127.0.0.1:6379(TX)> SET b 1QUEUED127.0.0.1:6379(TX)> EXEC1) OK2) (integer) 23) OK

MULTI命令之后的操作都添加到了队列中。最后执行EXEC后再依次的执行每一个命令。

127.0.0.1:6379> MULTIOK127.0.0.1:6379(TX)> SET a 1QUEUED127.0.0.1:6379(TX)> DISCARDOK127.0.0.1:6379> keys *(empty array)

DISCARD放弃操作

127.0.0.1:6379> MULTIOK127.0.0.1:6379(TX)> SET a 1QUEUED127.0.0.1:6379(TX)> DISCARDOK127.0.0.1:6379> keys *(empty array)

WATCH演示

开启2个CMD窗口

第一个执行WATCH、MULTI、EXEC

127.0.0.1:6379> set version 1OK127.0.0.1:6379> WATCH versionOK127.0.0.1:6379> MULTIOK127.0.0.1:6379(TX)> set a 1QUEUED127.0.0.1:6379(TX)> set b 1QUEUED

到此不执行EXEC或DISCARD

第二个执行修改version

127.0.0.1:6379> INCR version(integer) 2

到此再回到第一个窗口继续执行

127.0.0.1:6379(TX)> exec(nil)127.0.0.1:6379> keys *1) "version"

此时我们在MULTI后面添加的命令都没有执行,因为在第二个窗口中我们修改了version的值,所以这里EXEC后不会执行任何的命令。

3. SpringBoot中应用

在SpringBoot中使用Redis乐观锁,再结合retry框架来实现重试的功能。

引入依赖

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-data-redis</artifactId></dependency>

配置redis

spring:  redis:    host: localhost    port: 6379    password:     lettuce:      pool:        maxActive: 8        maxIdle: 100        minIdle: 10        maxWait: -1

代码实现

@Resourceprivate StringRedisTemplate stringRedisTemplate ;
// 重试,当发生IllegalStateException异常才进行重试,并且最多重试3次@Retryable(maxAttempts = 3, value = {IllegalStateException.class})public List<Object> watch() {  List<Object> ret = stringRedisTemplate.execute(new SessionCallback<List<Object>> () { @Override public List<Object> execute(RedisOperations opt) throws DataAccessException { // 执行watch key opt.watch("v") ; // 开始事务块,后续所有命令将加入队列 opt.multi() ; opt.opsForValue().increment("v") ; // 执行队列中的所有命令 return opt.exec() ; } });  // 当放弃队列中的任务后,这里的返回值将会为空。所以只需空判断即可 if (ret.isEmpty()) { System.err.printf("重试...%n") ;    // 这里抛出异常,进行重试 throw new IllegalStateException("数据被修改") ; } return ret ;}

总结:在SpringBoot中,通过使用Redis的Watch机制,可以实现乐观锁。这种锁机制可以有效地解决并发访问数据时可能出现的冲突问题,提高系统的并发性能。但是,需要注意的是,在事务执行过程中,如果被监控的key发生变化,会进行重试操作,这可能会对系统性能产生一定的影响。因此,在使用乐观锁时,需要根据具体业务场景进行权衡和选择。

完毕!!!

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读38
粉丝0
内容832