目录
什么是事务?
事务是一个单独的隔离操作:事务中所有的命令都会序列化、按顺序的执行。事务在执行的过程中,不会被客户端发来的命令请求打断。
事务是一个原子性操作:事务里的命令要么全部执行,要么全部不执行。
Redis事务的概述
redis采用了乐观锁的方式进行事务控制,使用watch监视一定的key,当exec(提交)的时候,如果监视的key从执行watch之后发生了变化,则整个事务会失败。
如果watch在监视过程中,连接断开,监视和事务会自动清除。exec,discard,unwatch都会清除连接中的所有监视。
Redis事务基本指令
multi 开启事务
exec 提交事务
discard 取消事务
watch 监控,如果监控的值反生变化,则提交事务会失败
unwatch 去掉监控
实践
exec提交事务
模拟转账,tony给Jack转账100
127.0.0.1:6379> set tony 500
OK
127.0.0.1:6379> set jack 200
OK
127.0.0.1:6379> mget tony jack
1) "500"
2) "200"
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379(TX)> decrby tony 100 #所有指令操作会进入到队列
QUEUED
127.0.0.1:6379(TX)> incrby jack 100
QUEUED
127.0.0.1:6379(TX)> mget tony jack
QUEUED
127.0.0.1:6379(TX)> exec #提交事务
1) (integer) 400
2) (integer) 300
3) 1) "400"
2) "300"
127.0.0.1:6379> mget tony jack
1) "400"
2) "300"
127.0.0.1:6379>
客户端中买票操作实践(demo)
package com.jt.demos;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;
import java.util.List;
/**
* redis秒杀练习:
* 模拟两个线程都去抢购同一张票(考虑乐关锁)
*/
public class SecondKillDemo02 {
public static void secKill(){
Jedis jedis=new Jedis("192.168.126.130",6379);
jedis.auth("123456");
jedis.watch("ticket","money");
String ticket = jedis.get("ticket");
if(ticket==null||Integer.valueOf(ticket)==0)
throw new RuntimeException("已无库存");
Transaction multi = jedis.multi();
try {
multi.decr("ticket");
multi.incrBy("money", 100);
List<Object> exec = multi.exec();
System.out.println(exec);
}catch (Exception e){
e.printStackTrace();
multi.discard();
}finally {
jedis.unwatch();
jedis.close();
}
}
public static void main(String[] args) {
Jedis jedis=new Jedis("192.168.126.130",6379);
jedis.auth("123456");
jedis.set("ticket","1");
jedis.set("money","0");
Thread t1=new Thread(()->{
secKill();
});
Thread t2=new Thread(()->{
secKill();
});
t1.start();
t2.start();
}
}
面试题
redis里支持什么特性?
支持一致性和隔离性,当appendfsync的值为always时,事务也具有持久性。
redis事务支持隔离性吗?
redis是单进程程序,执行期间不会被其他进程打断,带有隔离性。
redis支持原子性吗?
redis中命令是原子性执行的,但是事务部保证原子性,且没有回滚。事务中任意命令执行失败,其他命令也会执行成功。