Retrying Multi-statement Transactions
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(); } }