Redis 事务是指将多条命令加入队列,一次批量执行多条命令,每条命令会按顺序执行,事务执行过程中不会受客户端传入的命令请求影响。本文将介绍通过 jedis 发起和执行 Redis 事务。
jedis 事务通过 multi() 开始,该方法将返回一个 Transaction 对象,我们可以利用 Transaction 对象进行事务操作,如:exec() 提交事务。
开启 Redis 事务,然后保存用户基础信息、地址信息,最后保存用户和地址之间的关系信息。代码如下:
// 开启事务 Transaction transaction = this.jedis.multi(); /** * 事务内容 */ // 保存用户信息 Map<String,String> userHash = new HashMap<String,String>(); userHash.put("id", "1001"); userHash.put("name", "张三"); userHash.put("sex", "男"); userHash.put("age", "27"); String userId = "users:" + userHash.get("id"); transaction.hmset(userId, userHash); // 事务操作1 // 保存地址信息(多个地址) Map<String,String> addressHash = new HashMap<String, String>(); addressHash.put("work", "工作地址"); addressHash.put("family", "家庭地址"); addressHash.put("school", "学习地址"); String addressId = "address:" + userHash.get("id"); transaction.hmset(addressId, addressHash); // 事务操作2 // 保存用户和地址间的关系 transaction.hset("userAddress", userId, addressId); // 事务操作3 // 提交事务 List<Object> result = transaction.exec(); System.out.println("结果:" + result); System.out.println(userId + "=" + this.jedis.hgetAll(userId) ); System.out.println(addressId + "=" + this.jedis.hgetAll(addressId) ); System.out.println(userId + "=" + this.jedis.hget("userAddress", userId) );
运行代码,输出如下:
结果:[OK, OK, 1] users:1001={sex=男, name=张三, id=1001, age=27} address:1001={school=学习地址, work=工作地址, family=家庭地址} users:1001=address:1001
从上面结果可知,transaction.exec() 返回了一个 List 列表,列表中表示了事务操作每个步骤的返回结果。
注意:使用事务修改 Redis 指定类型的数据时需要使用 Transaction 对象提供的方法,而不是 jedis 提供的方法。如使用 transaction.hset(),而不是 jedis.hset()。
还有一点我们需要特别注意,Redis 事务和关系型数据库的事务不太一样,它不保证原子性,也没有隔离级别的概念。下面就通过代码演示:
String key1 = "t1"; String key2 = "t2"; this.jedis.msetnx(key1, "Tomcat", key2, "male"); System.out.println( key1 + "=" + this.jedis.get(key1) ); System.out.println( key2 + "=" + this.jedis.get(key2) ); // 开启事务 Transaction transaction = this.jedis.multi(); transaction.set(key1, "Hibernate"); // 在字符串上面进行incrby操作将会抛出错误 transaction.incrByFloat(key2, 12.5D); // 提交事务 transaction.exec(); // 从输出的结果可以看出,并没有进行回滚 System.out.println( key1 + "=" + this.jedis.get(key1) ); System.out.println( key2 + "=" + this.jedis.get(key2) );
运行代码,输出如下:
t1=Tomcat t2=male t1=Hibernate t2=male
通过上面输出结果可知,t1 键的值已经被修改,当 jedis 抛错的时候并不会进行回滚。