您的位置:首页 > 数据库 > Redis

RedisTemplate 事务处理方法 watch multi exec 的使用

2018-09-06 10:50 651 查看
SpringBoot RedisTemplate 事务处理方法 watch multi exec 的使用
1. 前言
在分布式环境下,对redis中的同一个变量进行操作,如果不注意,很容易就出现数据错乱的问题,简单的例子有10个线程,
同时对某个变量(0)进行+1的操作,正常情况下,变量的最终值应该是10,但如果处理不当,最终值有可能不是10

2. 有问题的代码
String key = "multThreadTest";

redisTemplate.delete(key);

Runnable runable = new Runnable() {
@Override
public void run() {
int count = 0;
String value = (String) redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(value)) {
count = Integer.parseInt(value);
}
count = count + 1;
redisTemplate.opsForValue().set(key, String.valueOf(count));
}
};

List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(runable, "thread-" + (i + 1));
thread.start();
threads.add(thread);
}

for (Thread thread : threads) {
thread.join();
}

String value = redisTemplate.opsForValue().get(key);
System.out.println("value:" + value);

可以看到,上面的代码,每次执行得到的结果都不一样

2. 正确处理的代码
String key = "multThreadTest";

redisTemplate.delete(key);

Runnable runable = new Runnable() {
@Override
public void run() {

redisTemplate.execute(new SessionCallback<Object>() {

@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object execute(RedisOperations operations) throws DataAccessException {
List<Object> result = null;
do {
int count = 0;
operations.watch(key);  // watch某个key,当该key被其它客户端改变时,则会中断当前的操作
String value = (String) operations.opsForValue().get(key);
if (!StringUtils.isEmpty(value)) {
count = Integer.parseInt(value);
}
count = count + 1;
operations.multi(); //开始事务
operations.opsForValue().set(key, String.valueOf(count));
try {
result = operations.exec(); //提交事务
} catch (Exception e) { //如果key被改变,提交事务时这里会报异常

}
} while (result == null); //如果失败则重试
return null;
}

});

}
};
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(runable, "thread-" + (i + 1));
thread.start();
threads.add(thread);
}

for (Thread thread : threads) {
thread.join();
}

String value = redisTemplate.opsForValue().get(key);
System.out.println(value);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息