### redis 的事务
* watch 用于标记一个key,当这个key在其他连接中被更改的时候,`exec` 命令会执行失败,返回null
* unwatch 清除一个key的标记,exec执行时会清除之前的所有标记
* multi 开始 事务,之后所有的命令都会暂存
* discard 删除之前的事务暂存,并退出事务
* exec 执行暂存命令,并返回执行结果列表
通常的redis事务
```redis
multi
set keyaaa xxx
set keybbb xxx
exec
```
你可以需要读取一些值,然后修改它
```redis
watch keya
get keya
multi
# other set action
exec
```
> 注意在 `multi` 和 `exec` 之间执行的读取参数不会返回值,尤其在java中,可能会导致空指针异常。
所以需要 `watch key` 然后再读取
所以简单来说redis事务的主要结构
```
watch key
# 执行读取操作
multi
# 执行更新操作
exec
```
如果 key被其他连接更改了,这时exec会执行失败,根据业务需求可能需要重置。
换用java就是
```java
SessionCallback<String> callback = new SessionCallback<String>() {
@Override
public <K, V> String execute(RedisOperations<K, V> operations)
throws DataAccessException {
operations.watch();
// Read
operations.multi();
// Write operations
operations.exec();
}
};
redisTemplate.execute(callback);
```
> 需要注意的是 redisTemplate 的 execute 有两个入参类型,分别是 `SessionCallback` 和 `RedisCallback`,如果要使用事务的话,一定要传 `SessionCallback` ,因为 `RedisCallback` 并不保证执行的命令都在一个会话中
同时 redis 也可以使用 lua 脚本来保证原子性 ,这个后续再去探索
[参考原文](https://github.com/eric-wu/dashboard/wiki/3.-Redis-Transactions-via-Spring-Data-Redis)
【学习笔记】java 中的 redis 事务