一个临时的功能:当用户登录系统时,如果用户不存在,则为该用户初始化一些身份信息。在入库的时候发现存在一些并发行为,可能会初始化两条用户信息,这种问题需要规避,所以我决定用锁。
因为初始化信息的时候,是插入操作,所以行锁是用不了的,我需要用表锁,但是用表锁又会印象到其他接口的查询功能(是这样的吧?我这块学的还不透彻)。所以,我最终决定用Redis实现一个简单的分布式锁。
分布式锁原理比较简单,就是利用了Redis的单线程性,我直接找了一个线程的Jar包,操作步骤如下:
- 引入Jar包
1
2
3
4
5
6
7
|
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.12.5</version>
</dependency>
|
- 进行配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private Integer port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.lettuce.pool.max-idle}")
private int maxPoolSize;
private String cluster;
@Bean
public RedissonClient redissonClient() {
return loadRedisson();
}
public RedissonClient loadRedisson() {
RedissonClient redisson;
Config config = new Config();
//单节点
if (!StringUtils.isEmpty(host)) {
config.useSingleServer()
.setAddress("redis://" + host + ":" + port)
.setPassword(StringUtils.isEmpty(password) ? null : password)
.setConnectionPoolSize(maxPoolSize)
.setDnsMonitoringInterval(-1)
//最小空闲连接
.setConnectionMinimumIdleSize(0);
} else {
//集群节点
String[] nodes = cluster.split(",");
//redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加
for (int i = 0; i < nodes.length; i++) {
nodes[i] = "redis://" + nodes[i];
}
//这是用的集群server
config.useClusterServers()
//设置集群状态扫描时间2000
.setScanInterval(2000)
.addNodeAddress(nodes)
.setPassword(password)
.setMasterConnectionPoolSize(maxPoolSize)
.setDnsMonitoringInterval(-1)
//最小空闲连接
.setMasterConnectionMinimumIdleSize(0);
}
redisson = Redisson.create(config);
return redisson;
}
public RedissonClient retryGetRedisson() {
return loadRedisson();
}
}
|
- 编写代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
RLock lock = redissonClient.getLock(String.format("SRM:inviteFromMaterialPlatform:%s_%s", tenantId, request.getSupplierId()));
try {
lock.lock();
// do something
return inviteInsert.getId();
} finally {
if (lock.isLocked()) {
lock.unlock();
}
}
|
遇到的问题:
- 因为我使用了Proxifier代理java.exe的所有流量,从而让我本地的服务可以直接访问K8S集群中的服务。但是,使用该工具的时候,会一直报redis不可解析,我已经在我的代码服务器中设置了该host条目。最后解决该问题的方法是:我在我本机的host文件中加上了该host条目,我感觉这种解决问题的方式不是很优雅。