概念:
1:事务是redis中的最小执行单元。在事务中封装一组命令,要么都执行要么都不执行。
2:redis中的事务没有回滚概念,它只检验语法错误不检验运行时错误,即如果多条命令语法正确是会全部执行的但如果第其中一条发生运行错误,那么其它命令会执行成功而那条发生错误的命令则执行失败,这是和spring事务管理不一样的。
3:redis会将一个事务中的所有命令全部发送到缓存中然后依次执行这些命令,因为redis是单线程的所以在执行一个事务时是不会执行其它客户端发来的命令的。
4:因为redis是基于内存的所以即便是单线程它的速度依然是可以的。
Redis-cli中事务操作
一:multi命令开启事务,discard命令关闭事务,exec命令提交事务
当开启事务时通过set命令创建key后返回的不再是ok而是QUEUED,redis会将这个三个命令发送到缓存当执行exec时会依次执行三个命令,在执行时是不会去执行其它命令的。
二:没有事务回滚
上例中第三条命令lpush k3 a bc本身语法是正确的,但是k3是之前定义的一个string类型key所以通过lpush进行赋值时会报错误wrongtype,所以在执行exec后前两条执行成功返回ok最后一条报错而并没有整体回滚。
三:watch命令
当我们get到一个key的value后对它进行操作同时不希望别的事务对它进行操作,注意此时get和操作命令是一体的所以这时不能使用事务将它们封装在一起,事务不包含查询命令。那么我可以使用watch命令对key进行监控。
下例说明:
1:程序开始执行通过watch监控k1
2:当休眠时我在redis-cli中执行set k1 10命令模拟其它事务已经修改了k1
3:判断formatted,为null时监控到有其它事务有修改则阻止本事务中的其它操作,不为null时则可以执行本事务操作。
本事务中的操作是k1+1,当其它事务有修改并被监控后阻止了k1+1(10),然后重新调用本事务方法,第二次执行时没有其它事务修改所以执行k1+1(11)。
4:watch命令只能监控不能阻止其它事务操作。
5:执行unwatch命令和exec命令则撤销监控。
@Test
public void testWatch() throws InterruptedException
{
//1:从jedis连接池中获取链接
Jedis jedis = RedisTools.getJedis();
//2:使用watch命令监控k1,可同时监控多个key
jedis.watch("k1");
//3:获得k1的值并加1
String value = jedis.get("k1");
int num = Integer.valueOf(value);
num++;
//4:此处休眠10秒模拟有其他客户端在修改k1,我们通过redis-cli来完成此操作
Thread.sleep(10000);
//5:事务操作,k1的value加1
Transaction multi = jedis.multi();
multi.set("k1", num + "");
List<Object> formatted = multi.exec();
//6:根据监控判断本事务是否执行
if(null == formatted)
{
System.out.println("监控到有其他事务修改k1,阻止本事务的操作");
System.out.println("k1:" + jedis.get("k1"));
testWatch();
}
else
{
System.out.println("没有其他事务修改k1,本事务正常执行");
System.out.println("k1:" + jedis.get("k1"));
}
}