赞
踩
Reids事务
1.在Redis中,也许存在多个客户端同时向Redis系统发送命令的并非的可能性,因此同一份数据可能被不同线程所操控,这样就出现了并发下的数据一致问题。
事物是一个被隔离的操作,事务中的方法都会被Redis按顺序执行,事务在执行过程中不会被其他客户端发生的命令所打断。例如,在Redis中开启事务是multi命令,执行事务是exec命令,开启到执行命令之间,Redis采取的是进入队列的形式,直到exec命令出现,才会一次性发送队列里的命令去执行,而在执行这些命令的时候其他客户端就不能再插入任何命令
2.事务的具体操作
//使用Redis事务 @Test public void TestRedisTransaction() { RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class); /*edisTemplate直接调用opfor..来操作redis数据库,每执行一条命令是要重新拿一个连接,因此很耗资源, 让一个连接直接执行多条语句的方法就是使用SessionCallback*/ SessionCallback<Object> callback = new SessionCallback<Object>() { @Override public Object execute(RedisOperations operations) throws DataAccessException { String value1=null; operations.multi(); operations.opsForValue().set("name", "qinyi"); value1 = (String) operations.opsForValue().get("name"); operations.opsForValue().get("gender"); operations.opsForValue().get("age"); System.out.println("命令只是进入了队列,而没有被执行,所以此时value1应为空:"+value1); operations.opsForValue().set("gender", "male"); operations.opsForValue().set("age", "19"); List<Object> list = operations.exec(); value1 = (String) operations.opsForValue().get("name"); System.out.println("执行了exec()就不为空:"+value1); System.out.println("list:"+list); return list; } }; //执行Redis命令 List<Object> value = (List<Object>) redisTemplate.execute(callback); System.out.println("excute方法的的返回值:"+value); }
运行结果:
可以看到没有exec()命令之前get方法返回值一律为空,最后使用redisTemplate.execute执行我们再SessionCallBack的业务逻辑,否则将不会执行SessionCallBack中的内容;
事务回滚
如上代码
@Test public void TestRedisTransaction() { RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class); /*edisTemplate直接调用opfor..来操作redis数据库,每执行一条命令是要重新拿一个连接,因此很耗资源, 让一个连接直接执行多条语句的方法就是使用SessionCallback*/ SessionCallback<Object> callback = new SessionCallback<Object>() { @Override public Object execute(RedisOperations operations) throws DataAccessException { String value1=null; operations.multi(); operations.opsForValue().set("name", "qinyi"); value1 = (String) operations.opsForValue().get("name"); operations.opsForValue().get("gender"); operations.opsForValue().get("age"); System.out.println("命令只是进入了队列,而没有被执行,所以此时value1应为空:"+value1); operations.opsForValue().set("gender", "male"); operations.opsForValue().set("age", "19"); **operations.discard(); //事务回滚 当事务回滚后还进行exec命令,会报异常** List<Object> list = operations.exec(); value1 = (String) operations.opsForValue().get("name"); System.out.println("执行了exec()就不为空:"+value1); System.out.println("list:"+list); return list; } }; //执行Redis命令 List<Object> value = (List<Object>) redisTemplate.execute(callback); System.out.println("excute方法的的返回值:"+value); }
对于Redis而言,其回滚能力也和数据库不太一样。需要特别注意两个地方:
1.Redis事务遇到命令格式正确而数据类型不符合时
例如:
@Test public void TestRedisRollback() { RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class); SessionCallback<Object> callback = new SessionCallback<Object>() { @Override public Object execute(RedisOperations operations) throws DataAccessException { operations.multi(); //这里我设置了String类型的字符串 operations.opsForValue().set("number","asd1"); operations.opsForValue().set("哈哈","sdsd"); //对字符串执行+1操作 operations.opsForValue().increment("number", 1); return operations.exec(); } }; System.out.println(redisTemplate.execute(callback)); }
虽然控制台抛出了异常,但是其之前之后的命令依然set了进去,没有回滚。
2.Redis对于命令格式错误却是另外一种情况
如图我们开启缓存 同样像执行增加操作,但是故意将命令输入错误 然后再提交,而出现这种命令格式错误,redis前后都直接回滚了,得到的值都为空
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。