在传统的关系型数据当中,使用事务是我们最常见的操作。来到Redis当中这里有事务吗,Redis是支持事务的。但是这个事务跟关系型数据库的传统事务不一样,在关系型数据库当中我们可以对出现错误的sql进行回滚,但是在redis是没有这一说的。
在Redis事务当中,所有操作都是在提交的统一执行的,所以并没有回归操作,其实这个事务更像是批处理的感觉。以下就是事务常用的命令:
1、watch
2、unwatch
3、multi
4、exec
5、discard
以下就是使用Jedis使用事务的代码:
public static void main(String args[]){ GenericObjectPoolConfig config = new GenericObjectPoolConfig(); config.setMaxIdle(8); config.setMaxTotal(10); config.setMinIdle(2); config.setMaxWaitMillis(3000); jedisPool = new JedisPool(config, "localhost"); Jedis conn = jedisPool.getResource(); Transaction transaction = conn.multi(); Response<Long> newListPushResult = transaction.rpush("newList","A","B","C"); Response<List<String>> newListResponse = transaction.lrange("newList",0,-1); transaction.exec(); System.out.println("newListPushResult : " + newListPushResult.get()); for (String item : newListResponse.get()) { System.err.println( item + " "); } conn.close(); }
通过代码我们可以看到我们的执行结果是在exec之后才统一返回,所以Jedis会用一个Response对象最为事务对象transaction的执行放回值。如果我们在transaction执行exec方法之前调用response对象的get方法会出现异常:
Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: Please close pipeline or multi block before calling this method.
事实上我们还可以使用exec方法的返回值获得事务执行过程的结果,但是这个显然是不够方便的:
public static void main(String args[]){ GenericObjectPoolConfig config = new GenericObjectPoolConfig(); config.setMaxIdle(8); config.setMaxTotal(10); config.setMinIdle(2); config.setMaxWaitMillis(3000); jedisPool = new JedisPool(config, "localhost"); Jedis conn = jedisPool.getResource(); Transaction transaction = conn.multi(); transaction.rpush("newList","A","B","C"); transaction.lrange("newList",0,-1); List<Object> result = transaction.exec(); System.out.println("newListPushResult : " + result.get(0)); List<String> newListValues = (List<String>) result.get(1); for (String item : newListValues) { System.err.println( item + " "); } conn.close(); }
事务其中最为只要的功能是实现锁,redis提供一个watch命令。watch是一种乐观锁,watch命令的参数为key,当我们watch了一个key的时候,在事务执行之前被修改了,事务是不会执行成功的。只要我们在watch到事务执这段时间未被修改事务才会执行成功。当然如果我们在业务的中途不需要监控这个key的变化了也可以使用unwatch命令进行取消watch。以下是watch在jedis事务代码上的使用(下面会模拟一段购买商品的业务):
public static void main(String args[]){ GenericObjectPoolConfig config = new GenericObjectPoolConfig(); config.setMaxIdle(8); config.setMaxTotal(10); config.setMinIdle(2); config.setMaxWaitMillis(3000); jedisPool = new JedisPool(config, "localhost"); Jedis conn = jedisPool.getResource(); //market 有序集合 score 商品价格 member 商品名称 conn.zadd("market",100,"ProductA"); conn.zadd("market",33,"ProductB"); //用户对象 conn.hset("user:1","funds","900"); //监控market和user:1两个KEY的变化 conn.watch("user:1"