当前位置:   article > 正文

Redis(3)---事务_reids3.如何开启和执行事务?

reids3.如何开启和执行事务?

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);
	   
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

运行结果:
在这里插入图片描述
可以看到没有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);
	   
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

对于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));			
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述
在这里插入图片描述
虽然控制台抛出了异常,但是其之前之后的命令依然set了进去,没有回滚。
2.Redis对于命令格式错误却是另外一种情况
在这里插入图片描述如图我们开启缓存 同样像执行增加操作,但是故意将命令输入错误 然后再提交,而出现这种命令格式错误,redis前后都直接回滚了,得到的值都为空

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/318412
推荐阅读
相关标签
  

闽ICP备14008679号