[[tx]]
= Redis Transactions

Redis provides support for https://redis.io/topics/transactions[transactions] through the `multi`, `exec`, and `discard` commands.
These operations are available on `RedisTemplate`.
However, `RedisTemplate` is not guaranteed to run all the operations in the transaction with the same connection.

Spring Data Redis provides the `SessionCallback` interface for use when multiple operations need to be performed with the same `connection`, such as when using Redis transactions.The following example uses the `multi` method:

[source,java]
----
//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` uses its value, hash key, and hash value serializers to deserialize all results of `exec` before returning.
There is an additional `exec` method that lets you pass a custom serializer for transaction results.

[[tx.spring]]
== `@Transactional` Support

By default, `RedisTemplate` does not participate in managed Spring transactions.
If you want `RedisTemplate` to make use of Redis transaction when using `@Transactional` or `TransactionTemplate`, you need to be explicitly enable transaction support for each `RedisTemplate` by setting `setEnableTransactionSupport(true)`.
Enabling transaction support binds `RedisConnection` to the current transaction backed by a `ThreadLocal`.
If the transaction finishes without errors, the Redis transaction gets commited with `EXEC`, otherwise rolled back with `DISCARD`.
Redis transactions are batch-oriented.
Commands issued during an ongoing transaction are queued and only applied when committing the transaction.

Spring Data Redis distinguishes between read-only and write commands in an ongoing transaction.
Read-only commands, such as `KEYS`, are piped to a fresh (non-thread-bound) `RedisConnection` to allow reads.
Write commands are queued by `RedisTemplate` and applied upon commit.

The following example shows how to configure transaction management:

.Configuration enabling Transaction Management
====
[source,java]
----
@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> Configures a Spring Context to enable {spring-framework-docs}/data-access.html#transaction-declarative[declarative transaction management].
<2> Configures `RedisTemplate` to participate in transactions by binding connections to the current thread.
<3> Transaction management requires a `PlatformTransactionManager`.
Spring Data Redis does not ship with a `PlatformTransactionManager` implementation.
Assuming your application uses JDBC, Spring Data Redis can participate in transactions by using existing transaction managers.
====

The following examples each demonstrate a usage constraint:

.Usage Constraints
====
[source,java]
----
// 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");
----
====
