目录
Redis事务简介
- 概述
- 事务是一个业务,也可以看成是一个逻辑工作单元,是为了保证业务的完整,数据的正确而推出的一种控制机制,原则上来讲,事务必须要满足ACID四个特性(原子性,一致性,隔离性,持久性),在多个事务
- 在并发执行,为更好保证事务的四个特性的实现,通常会对事务加锁,Redis为了性能,采用了乐观锁方式进行事务控制,它使用watch命令监视给定的key,当exec(提交事务)的时候,如果监视的key从调用watch后发生过变化,则整个事务会失败。也可以调用watch多次监视多个key。注意watch的key是对整个连接有效的,如果连接断开,监视和事务都会被自动清除。当然exec,discard,unwatch命令都会清除连接中的所有监视。
基本指令
- multi 开启事务
- exec 提交事务
- discard 取消事务
- watch 监控,如果监控的值发生变化,则提交事务时会失败,类似乐观锁
- unwatch 去掉监控
- Redis保证一个事务中的所有命令要么都执行,要么都不执行(原子性)。如果在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。
- 当出现错误指令时,事务也会自动取消。
Jedis 客户端事务操作
package com.jt.transactionTestsDemo;
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.129",6379);
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.129",6379);
jedis.set("ticket","1");
jedis.set("money","0");
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
secKill();
}
});Thread t2=new Thread(new Runnable() {
@Override
public void run() {
secKill();
}
});
Thread t3=new Thread(()->{
secKill();
});
Thread t4=new Thread(()->{
secKill();
});
t1.start();
t3.start();
t4.start();
t2.start();
}
}
package com.jt;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
public class JedisTransactionTests {
@Test
public void testJedisTransaction(){
Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.set("tony", "500");
jedis.set("tom", "300");
//实现操作,tony转账100给jack
//开启事务
Transaction multi = jedis.multi();
//执行业务操作
try {
multi.decrBy("tony", 100);
multi.incrBy("jack", 100);
int n=100/0;//模拟异常
//提交事务
multi.exec();
}catch(Exception e) {
//出现异常取消事务
multi.discard();
}
String tonyMoney=jedis.get("tony");
String jackMoney=jedis.get("jack");
System.out.println("tonyMoney="+tonyMoney);
System.out.println("jackMoney="+jackMoney);
jedis.close();
}
}