A newer version of this documentation is available.

View Latest

Distributed Transactions Migration Guide

      +
      For those transitioning from using the Couchbase Transactions library for Java.

      Couchbase transactions for Java were originally introduced as a library separate from the Couchbase Java SDK.

      We subsequently chose to integrate transactions directly into the SDKs with the release of Java SDK 3.3.0, to make it easier for users to get started.

      This document details the small changes that existing users of the legacy transactions library need to make, to migrate to the SDK-integrated version.

      The legacy transactions library will continue to be supported with bugfixes for some time, but new transaction features will only be added to the SDK and it is recommended that all users migrate.

      Accessing transactions

      This is now done via a Cluster object. There is no longer any need to create a Transactions object.

      Before
      var transactions = Transactions.create(cluster);
      
      transactions.run((ctx) -> {
          // Your transaction logic.
      });
      After
      cluster.transactions().run((ctx) -> {
          // Your transaction logic.
      });

      Configuration

      Configuration used to be performed when creating the Transactions object, and is now performed when creating the Cluster object.

      Before
      var transactions =
        Transactions.create(cluster,
          TransactionConfigBuilder.
            .durabilityLevel(TransactionDurabilityLevel.MAJORITY)
            .metadataCollection(collection));
      After
      var keyspace = TransactionKeyspace.create("bucketName", "scopeName", "collectionName");
      
      var cluster = Cluster.connect("localhost", ClusterOptions.clusterOptions("username", "password")
              .environment(env -> env.transactionsConfig(TransactionsConfig
                      .durabilityLevel(DurabilityLevel.PERSIST_TO_MAJORITY)
                      .metadataCollection(keyspace))));

      A few details of configuration change:

      • TransactionsConfig::metadataCollection takes a TransactionKeyspace instead of a Collection (since a Collection cannot be created at this point).

      • keyValueTimeout has been removed from TransactionsConfig and TransactionOptions.

      • TransactionDurabilityLevel has been dropped in favour of using the SDK’s DurabilityLevel.

      • TransactionOptions now allows a metadataCollection parameter.

      And certain classes have been renamed to be compliant with the Java SDK:

      Before After

      TransactionConfigBuilder

      TransactionsConfig

      TransactionQueryConfigBuilder

      TransactionsQueryConfig

      SingleQueryTransactionConfigBuilder

      SingleQueryTransactionOptions

      PerTransactionConfigBuilder

      TransactionOptions

      Cleanup configuration

      Cleanup configuration options have been encapsulated into their own class:

      Before
      var transactions =
        Transactions.create(cluster,
          TransactionConfigBuilder.create()
            .cleanupClientAttempts(false)
            .cleanupLostAttempts(false)
            .cleanupWindow(Duration.ofSeconds(30)));
      After
      var cluster = Cluster.connect("localhost", ClusterOptions.clusterOptions("username", "password")
              .environment(env -> env.transactionsConfig(TransactionsConfig
                              .cleanupConfig(TransactionsCleanupConfig
                                      .cleanupClientAttempts(true)
                                      .cleanupLostAttempts(true)
                                      .cleanupWindow(Duration.ofSeconds(30))))));

      Lambda

      ctx.commit() has been removed, as it is redundant: commit automatically happens when the lambda successfully reaches the end.

      ctx.rollback() has been removed, as it too is redundant: the application can throw any exception from the lambda to trigger a rollback.

      ctx.getOptional() has been replaced with ctx.get() throwing a DocumentExistsException. This may be caught, allowing the transaction to continue.

      Package changes

      All classes have changed packages to be compatible with the Java SDK conventions.

      The simplest way to convert many of the classes to their new locations is to search for import com.couchbase.transactions. and replace it with import com.couchbase.client.java.transactions..

      Some additional manual conversion after this may be required.

      Single query transactions

      These are now integrated with the existing SDK QueryOptions.

      Before
      SingleQueryTransactionResult sqr = transactions.query("INSERT...");
      After
      QueryResult qr = cluster.query("INSERT...", queryOptions().asTransaction());

      Or with configuration:

      Before
      SingleQueryTransactionResult sqr = transactions.query("INSERT...",
        SingleQueryTransactionConfigBuilder.create()
          .durabilityLevel(TransactionDurabilityLevel.MAJORITY));
      
      QueryResult qr = sqr.queryResult();
      After
      QueryResult qr = cluster.query("INSERT...",
              queryOptions().asTransaction(
                      singleQueryTransactionOptions()
                              .durabilityLevel(DurabilityLevel.MAJORITY)));

      Cleanup

      This doesn’t impact the API, but it is useful to know that lost cleanup has changed.

      Previously, lost cleanup would look for expired transactions on the default collections of all buckets in the cluster. Unless a metadata collection was specified, in which case only that collection would be cleaned up.

      Now, cleanup is dynamic. As transactions are run, the collection where metadata is created for that collection, is added to what we call the 'cleanup set'. This is just the set of collections where cleanup, for this application, is looking for expired transactions.

      The intent has always been that users without complex requirements should never need to think about or configure transaction cleanup, and this new dynamic cleanup allows us to be closer still to that goal.

      Naming

      All exceptions and events have been renamed to be compliant with the SDK. For example, TransactionFailed is now TransactionFailedException, and TransactionCleanupAttempt is now TransactionCleanupAttemptEvent.

      Logging

      TransactionFailedException now exposes the logs directly, rather than containing a nested TransactionResult.

      Before
      catch (TransactionFailedException err) {
          err.result().log().logs().forEach(msg -> logger.warning(msg.toString()));
      }
      After
      catch (TransactionFailedException err) {
          err.logs().forEach(msg -> logger.warning(msg.toString()));
      }

      Further Reading