1 redis的基础事务
在redis中,也存在多个客户端同时向Redis系统发送命令的可能性.为了保证数据的安全性,Redis提供了事务方案,Redis的事务使用MULTI-EXEC的命令组合,使用它可以提供两个重要的保证:
1)事务是一个被隔离的操作,事务中的方法都会被Redis进行序列化并按顺序执行,事务在执行的过程中不会被其他客户端发送的命令打断.
2)事务是一个原子性的操作,他要么全部执行,要么全部不执行.
3)Redis的事务会有3个过程:开启事务,命令进入队列,执行事务.Redis的事务命令如下:
muti:开启事务命令,之后的命令进入队列,而不会马上执行.在事务生存期间,所有的Redis关于数据结构的命令都会进入队列.
watch key1[key2…]:监听某些键,当被监听的键在事务执行前被修改,则事务会被回滚.
unwatch key1[key2…]:取消监听某些键
exec:执行事务,如果被监听的键没有被修改,则采用执行命令,否则就回滚命令.在执行事务队列存储的命令前,Redis会检测被监听的键值对有没有发生变化,如果没有则执行命令,否则就回滚事务.
discard:回滚事务.
使用linux命令执行事务:
如图,使用multi开启事务后,set和get命令不会马上执行,而是返回QUEUED,在执行exec后,命令才会真正执行
使用linux命令回滚事务:
如图,在执行discard命令后,事务中的命令就被取消了,再执行exec就会报错了.
在spring中使用redis事务命令
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
List<Object> txResults = (List<Object>) redisTemplate.execute(new SessionCallback<List<Object>>() {
public List<Object> execute(RedisOperations operations) throws DataAccessException {
operations.multi();
operations.opsForSet().add("key", "value1");
return operations.exec();
}
});
System.out.println("Number of items added to set: " + txResults.get(0));
2 redis事务回滚
1)命令格式正确,数据类型不符合
如图:key1设置为字符串,而使用incr对其自增,但是命令只会进入队列,而没有被执行,所以它不会有任何的错误.当exec命令执行后,之前进入队列的命令就依次执行,当遇到incr时发生命令操作的数据类型错误,而其之前之后的命令都会被正常执行.
2)命令格式错误
如图:incr命令的格式是错误的,这个时候redis会立即检测出来并产生错误,而之前之后的命令都被回滚了.
结论:在执行事务命令的时候,在命令入队的时候, Redis 就会检测事务的命令是否正确,如果不正确则会产生错误。无论之前和之后的命令都会被事务所回滚,就变为什么都没有执行。当命令格式正确,而因为操作数据结构引起的错误,则该命令执行出现错误,而其之前和之后的命令都会被正常执行
3 使用watch命令监控事务
在Redis 中使用watch 命令可以决定事务是执行还是回滚。一般而言,可以在multi 命令之前使用watch 命令监控某些键值对,然后使用multi 命令开启事务,执行各类对数据结构进行操作的命令,这个时候这些命令就会进入队列。当Redis 使用exec 命令执行事务的时候,它首先会去比对被watch 命令所监控的键值对,如果没有发生变化,那么它会执行事务队列中的命令,提交事务;如果发生变化,那么它不会执行任何事务中的命令,而去事务回滚.过程如下:
CAS乐观锁:
在线程开始时读取这些多线程共享的数据,并将其保存到当前进程的副本中,我们称为旧值( old value)。然后,开启线程业务逻辑,在执行更新前,比较当前线程副本保存的旧值和当前线程共享的值是否一致,如果不一致,那么该数据己经被其他线程操作过,此次更新失败。为了保持一致,线程就不去更新任何值,而将事务回滚:否则就认为它没有被其他线程操作过,执行对应的业务逻辑,乐观锁会导致ABA问题,如下:
因此仅仅记录一个旧值是不够的,还需要通过其他方法比米娜ABA的问题,常见的方法是给数据对象加上version. Redis 在执行事务的过程中, 并不会阻塞其他连接的并发,而只是通过比较w atch 监控的键值对去保证数据的一致性, 所以Redis 多个事务完全可以在非阻塞的多线程环境中井发执行,而且Redis 的机制是不会产生ABA 问题的.watch的使用如下: