Redis 事务
Redis 通过multi,exec和discard命令。
这些作可用于RedisTemplate.
然而RedisTemplate不保证使用同一连接运行事务中的所有作。
Spring Data Redis 提供了SessionCallback接口,用于需要使用相同的connection,例如在使用 Redis 事务时。以下示例使用multi方法:
//execute a transaction
List<Object> txResults = redisOperations.execute(new SessionCallback<List<Object>>() {
  public List<Object> execute(RedisOperations operations) throws DataAccessException {
    operations.multi();
    operations.opsForSet().add("key", "value1");
    // This will contain the results of all operations in the transaction
    return operations.exec();
  }
});
System.out.println("Number of items added to set: " + txResults.get(0));
RedisTemplate使用其 value、hash key 和 hash value 序列化器反序列化exec在返回之前。
还有一个额外的exec方法,该方法允许您为交易结果传递自定义序列化器。
值得一提的是,在multi()和exec()发生异常(例如,如果 Redis 在超时内没有响应,则超时异常),则连接可能会卡在事务状态。
为了防止这种情况,需要丢弃事务状态以清除连接:
List<Object> txResults = redisOperations.execute(new SessionCallback<List<Object>>() {
  public List<Object> execute(RedisOperations operations) throws DataAccessException {
    boolean transactionStateIsActive = true;
	try {
      operations.multi();
      operations.opsForSet().add("key", "value1");
      // This will contain the results of all operations in the transaction
      return operations.exec();
    } catch (RuntimeException e) {
	    operations.discard();
		throw e;
    }
  }
});
@Transactional支持
默认情况下,RedisTemplate不参与 managed Spring 事务。
如果需要帮助,RedisTemplate使用 Redis 事务时@Transactional或TransactionTemplate,您需要为每个RedisTemplate通过设置setEnableTransactionSupport(true).
启用事务支持绑定RedisConnection到由ThreadLocal.
如果事务完成且没有错误,则 Redis 事务将使用EXEC,否则回滚到DISCARD.
Redis 事务是面向批处理的。
在正在进行的事务期间发出的命令将排队,并且仅在提交事务时应用。
Spring Data Redis 区分正在进行的事务中的只读命令和写入命令。
只读命令,例如KEYS)通过管道传输到新的(非线程绑定)RedisConnection以允许读取。
写入命令按RedisTemplate并在提交时应用。
以下示例说明如何配置事务管理:
@Configuration
@EnableTransactionManagement                                 (1)
public class RedisTxContextConfiguration {
  @Bean
  public StringRedisTemplate redisTemplate() {
    StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory());
    // explicitly enable transaction support
    template.setEnableTransactionSupport(true);              (2)
    return template;
  }
  @Bean
  public RedisConnectionFactory redisConnectionFactory() {
    // jedis || Lettuce
  }
  @Bean
  public PlatformTransactionManager transactionManager() throws SQLException {
    return new DataSourceTransactionManager(dataSource());   (3)
  }
  @Bean
  public DataSource dataSource() throws SQLException {
    // ...
  }
}
| 1 | 配置 Spring Context 以启用声明式事务 Management。 | 
| 2 | 配置RedisTemplate通过将连接绑定到当前线程来参与事务。 | 
| 3 | 事务管理需要一个PlatformTransactionManager.
Spring Data Redis 不附带PlatformTransactionManager实现。
假设您的应用程序使用 JDBC,Spring Data Redis 可以使用现有的事务管理器参与事务。 | 
以下示例分别演示了使用约束:
// must be performed on thread-bound connection
template.opsForValue().set("thing1", "thing2");
// read operation must be run on a free (not transaction-aware) connection
template.keys("*");
// returns null as values set within a transaction are not visible
template.opsForValue().get("thing1");