Retrying Multi-statement Transactions
- Last Updated: April 14, 2026
- 2 minute read
MarkLogic Server sometimes detects the need to retry a transaction. For example, if the server detects a deadlock, it may cancel one of the deadlocked transactions, allowing the other to complete; the canceled transaction should be re-tried.
With single-statement, auto-commit transactions, the server can usually retry automatically because it has the entire transaction available at the point of detection. However, the statements in multi-statement transactions from XCC clients may be interleaved with arbitrary application-specific code of which the server has no knowledge.
In such cases, instead of automatically retrying, the server throws a RetryableXQueryException. The calling application is then responsible for re-trying all the requests in the transaction up to that point. This exception is more likely to occur when using multi-statement transactions.
The following example demonstrates logic for re-trying a multi-statement transaction. The multi-statement transaction code is wrapped in a retry loop with an exception handler that waits between retry attempts. The number of retries and the time between attempts is up to the application.
import java.net.URI;
import com.marklogic.xcc.ContentSource;
import com.marklogic.xcc.ContentSourceFactory;
import com.marklogic.xcc.Session;
import com.marklogic.xcc.exceptions.RetryableXQueryException;
public class TransactionRetry {
public static final int MAX_RETRY_ATTEMPTS = 5;
public static final int RETRY_WAIT_TIME = 1;
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("usage: xcc://user:password@host:port/contentbase");
return;
}
// Obtain a ContentSource object for the server at the URI.
URI uri = new URI(args[0]);
ContentSource contentSource =
ContentSourceFactory.newContentSource(uri);
// Create a Session and set the transaction mode to trigger
// multi-statement transaction use.
Session session = contentSource.newSession();
Session.setAutoCommit(false);
Session.setUpdate(Session.Update.TRUE);
// Re-try logic for a multi-statement transaction
for (int i = 0; i < MAX_RETRY_ATTEMPTS; i++) {
try {
session.submitRequest(session.newAdhocQuery(
"xdmp:document-insert('/docs/mst1.xml', <data/>)"));
session.submitRequest(session.newAdhocQuery(
"xdmp:document-insert('/docs/mst2.xml', fn:doc('/docs/mst1.xml'));"));
session.commit();
break;
} catch (RetryableXQueryException e) {
Thread.sleep(RETRY_WAIT_TIME);
}
}
session.close();
}
}