此版本仍在开发中,尚未被视为稳定版本。如需使用最新稳定版本,请访问 Spring Data Redis 4.0.4spring-doc.cadn.net.cn

Redis 事务

Redis 通过 multiexecdiscard 命令提供对 事务 的支持。 这些操作可在 RedisTemplate 上使用。 但是,RedisTemplate 并不保证使用同一连接执行事务中的所有操作。spring-doc.cadn.net.cn

Spring Data Redis 提供了 SessionCallback 接口,用于在执行多个操作时使用相同的 connection,例如在使用 Redis 事务时。以下示例使用了 multi 方法:spring-doc.cadn.net.cn

//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 在返回之前,会使用其值、哈希键和哈希值的序列化器对 exec 的所有结果进行反序列化。 还有一个额外的 exec 方法,允许你为事务结果传入自定义的序列化器。spring-doc.cadn.net.cn

值得一提的是,如果在 multi()exec() 之间发生异常(例如,当 Redis 在超时时间内未响应时抛出的超时异常),连接可能会陷入事务状态。 为防止出现这种情况,需要放弃事务状态以清理连接:spring-doc.cadn.net.cn

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 不参与受管理的 Spring 事务。 如果您希望在 @TransactionalTransactionTemplate 的使用过程中让 RedisTemplate 利用 Redis 事务,您需要通过设置 setEnableTransactionSupport(true) 为每个 RedisTemplate 显式启用事务支持。 启用事务支持会将 RedisConnection 绑定到当前事务,该事务由 ThreadLocal 提供支持。 如果事务顺利完成且无错误,Redis 事务将通过 EXEC 提交;否则将通过 DISCARD 回滚。 Redis 事务是面向批处理的。 在正在进行的事务中发出的命令会被排队,仅在提交事务时才应用。spring-doc.cadn.net.cn

Spring Data Redis 在正在进行的事务中区分只读命令和写命令。 只读命令(例如 KEYS)会被发送到一个全新的(非线程绑定的)RedisConnection,以允许执行读取操作。 写命令则由 RedisTemplate 进行排队,并在提交时执行。spring-doc.cadn.net.cn

以下示例展示了如何配置事务管理:spring-doc.cadn.net.cn

示例 1. 启用事务管理的配置
@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 上下文以启用声明式事务管理
2 配置 RedisTemplate 以通过将连接绑定到当前线程来参与事务。
3 事务管理需要一个 PlatformTransactionManager。 Spring Data Redis 本身并未提供 PlatformTransactionManager 的实现。 假设您的应用程序使用 JDBC,Spring Data Redis 可以通过使用现有的事务管理器参与事务。

以下每个示例都展示了一种使用限制:spring-doc.cadn.net.cn

示例 2. 使用限制
// 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");