A newer version of this documentation is available.

View Latest
February 16, 2025
+ 12
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
java
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
java
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
java
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
java
SingleQueryTransactionResult sqr = transactions.query("INSERT...");
After
QueryResult qr = cluster.query("INSERT...", queryOptions().asTransaction());

Or with configuration:

Before
java
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
java
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