Redis作为一款非关系型数据库,自然也拥有事务的支持,关系型数据库例如MySQL的事务具有ACID这四大基本特征,即Atomicity原子性,Consistency一致性,Isolation隔离性,Durability持久性。
Redis指令在multi创建事务之后,会被放入事务队列中,在exec之时会将指令依次从事务队列中提取出来执行,在discard之时会将事务队列抛弃。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YZhcYlLv-1572500173064)(http://note.youdao.com/yws/res/543/4B0F8FC9000A46839DC393E27E58C175)]
1.开启事务: multi命令用于开启事务,在开启事务之后,事务将不会被自动提交
127.0.0.1:6371> set arong test OK 127.0.0.1:6371> multi OK 127.0.0.1:6371> set arong test1 QUEUED 127.0.0.1:6371> set arong test2 QUEUED 127.0.0.1:6371> exec 1) OK 2) OK 127.0.0.1:6371> get arong "test2"2.提交事务 exec命令用于提交事务,提交的事务中若有失败也不会将全部指令都回滚掉,而是继续执行其他语句,所以Redis的事务不具备原子性,而只是提供了隔离性机制。
127.0.0.1:6371> set arong test OK 127.0.0.1:6371> multi OK 127.0.0.1:6371> rpush arong test1 QUEUED 127.0.0.1:6371> set arong test2 QUEUED 127.0.0.1:6371> exec 1) (error) WRONGTYPE Operation against a key holding the wrong kind of value 2) OK 127.0.0.1:6371> get arong "test2"3.回滚事务 discard命令用于回滚事务,回滚事务会将所有的指令抛弃。
127.0.0.1:6371> set arong test OK 127.0.0.1:6371> multi OK 127.0.0.1:6371> set arong test1 QUEUED 127.0.0.1:6371> set arong test2 QUEUED 127.0.0.1:6371> discard OK 127.0.0.1:6371> get arong "test"watch命令用于监控某个key,需要在开启事务前使用,它的作用是当事务开启后,若在提交事务时发现该key已经被更改过,那么所提交的指令全部回滚失效,否则正常提交。其实watch命令的实质是CAS算法,即比较后再决定是否是正确的预期。用一个给银行存款加倍的程序来演示一下:
public static int doubleAccount(Jedis jedis, String accountId) { while (true) { //监听该accountId的值 jedis.watch(accountId); int money = Integer.parseInt(jedis.get(accountId)); //开启事务 Transaction tx = jedis.multi(); //将钱款*2 tx.set(accountId, String.valueOf(money * 2)); //提交事务 List<Object> res = tx.exec(); if (res != null) { //提交事务成功 break; } } //返回当前余额 return Integer.parseInt(jedis.get(accountId)); }1.出于对性能的考虑 2.作者认为Redis事务应该在开发业务层面考虑