11package com .arangodb .springframework .transaction ;
22
3+ import com .arangodb .ArangoDBException ;
34import com .arangodb .ArangoDatabase ;
45import com .arangodb .DbName ;
56import com .arangodb .model .StreamTransactionOptions ;
67import com .arangodb .springframework .core .ArangoOperations ;
78import com .arangodb .springframework .repository .query .QueryTransactionBridge ;
8- import org .springframework .transaction .InvalidIsolationLevelException ;
9- import org .springframework .transaction .TransactionDefinition ;
10- import org .springframework .transaction .TransactionException ;
9+ import org .springframework .transaction .*;
1110import org .springframework .transaction .support .AbstractPlatformTransactionManager ;
1211import org .springframework .transaction .support .DefaultTransactionStatus ;
13-
14- import java .util .Collection ;
15- import java .util .function .Function ;
12+ import org .springframework .transaction .support .TransactionSynchronizationManager ;
1613
1714/**
1815 * Transaction manager using ArangoDB stream transactions on the
@@ -29,51 +26,97 @@ public class ArangoTransactionManager extends AbstractPlatformTransactionManager
2926 public ArangoTransactionManager (ArangoOperations operations , QueryTransactionBridge bridge ) {
3027 this .operations = operations ;
3128 this .bridge = bridge ;
29+ setNestedTransactionAllowed (false );
30+ setTransactionSynchronization (SYNCHRONIZATION_ALWAYS );
31+ setValidateExistingTransaction (true );
32+ setRollbackOnCommitFailure (true );
3233 }
3334
35+ /**
36+ * Creates a new transaction object. Any synchronized resource will be reused.
37+ */
3438 @ Override
35- protected Object doGetTransaction () throws TransactionException {
39+ protected Object doGetTransaction () {
3640 DbName database = operations .getDatabaseName ();
3741 if (logger .isDebugEnabled ()) {
3842 logger .debug ("Create new transaction for database " + database );
3943 }
40- return new ArangoTransaction (operations .driver ().db (database ));
44+ try {
45+ ArangoTransactionResource resource = (ArangoTransactionResource ) TransactionSynchronizationManager .getResource (database );
46+ return new ArangoTransactionObject (operations .driver ().db (database ), getDefaultTimeout (), resource );
47+ } catch (ArangoDBException error ) {
48+ throw new TransactionSystemException ("Cannot create transaction object" , error );
49+ }
4150 }
4251
52+ /**
53+ * Configures the new transaction object. The resulting resource will be synchronized and the bridge will be initialized.
54+ *
55+ * @see QueryTransactionBridge
56+ */
4357 @ Override
44- protected void doBegin (Object transaction , TransactionDefinition definition ) throws InvalidIsolationLevelException {
58+ protected void doBegin (Object transaction , TransactionDefinition definition ) throws TransactionUsageException {
4559 int isolationLevel = definition .getIsolationLevel ();
4660 if (isolationLevel != -1 && (isolationLevel & TransactionDefinition .ISOLATION_SERIALIZABLE ) != 0 ) {
4761 throw new InvalidIsolationLevelException ("ArangoDB does not support isolation level serializable" );
4862 }
49- ArangoTransaction tx = (ArangoTransaction ) transaction ;
63+ ArangoTransactionObject tx = (ArangoTransactionObject ) transaction ;
5064 tx .configure (definition );
51- bridge .setCurrentTransaction (tx ::getOrBegin );
65+ DbName key = operations .getDatabaseName ();
66+ rebind (key , tx .createResource ());
67+ bridge .setCurrentTransaction (collections -> {
68+ ArangoTransactionResource resource = tx .getOrBegin (collections );
69+ rebind (key , resource );
70+ return resource .getStreamTransactionId ();
71+ });
5272 }
5373
74+ /**
75+ * Commit the current stream transaction iff any. The bridge is cleared afterwards.
76+ */
5477 @ Override
5578 protected void doCommit (DefaultTransactionStatus status ) throws TransactionException {
56- ArangoTransaction tx = (ArangoTransaction ) status .getTransaction ();
79+ ArangoTransactionObject tx = (ArangoTransactionObject ) status .getTransaction ();
5780 if (logger .isDebugEnabled ()) {
5881 logger .debug ("Commit stream transaction " + tx );
5982 }
60- tx .commit ();
61- bridge .clearCurrentTransaction ();
83+ try {
84+ tx .commit ();
85+ bridge .clearCurrentTransaction ();
86+ } catch (ArangoDBException error ) {
87+ throw new TransactionSystemException ("Cannot commit transaction " + tx , error );
88+ }
6289 }
6390
91+ /**
92+ * Roll back the current stream transaction iff any. The bridge is cleared afterwards.
93+ */
6494 @ Override
6595 protected void doRollback (DefaultTransactionStatus status ) throws TransactionException {
66- ArangoTransaction tx = (ArangoTransaction ) status .getTransaction ();
96+ ArangoTransactionObject tx = (ArangoTransactionObject ) status .getTransaction ();
6797 if (logger .isDebugEnabled ()) {
6898 logger .debug ("Rollback stream transaction " + tx );
6999 }
70- tx .rollback ();
71- bridge .clearCurrentTransaction ();
100+ try {
101+ tx .rollback ();
102+ bridge .clearCurrentTransaction ();
103+ } catch (ArangoDBException error ) {
104+ throw new TransactionSystemException ("Cannot roll back transaction " + tx , error );
105+ }
72106 }
73107
74108 @ Override
75109 protected boolean isExistingTransaction (Object transaction ) throws TransactionException {
76- return transaction instanceof ArangoTransaction
77- && ((ArangoTransaction ) transaction ).exists ();
110+ return transaction instanceof ArangoTransactionObject && ((ArangoTransactionObject ) transaction ).exists ();
111+ }
112+
113+ @ Override
114+ protected void doCleanupAfterCompletion (Object transaction ) {
115+ TransactionSynchronizationManager .unbindResource (operations .getDatabaseName ());
116+ }
117+
118+ private static void rebind (DbName key , ArangoTransactionResource resource ) {
119+ TransactionSynchronizationManager .unbindResourceIfPossible (key );
120+ TransactionSynchronizationManager .bindResource (key , resource );
78121 }
79122}
0 commit comments