@@ -91,10 +91,28 @@ class Connection:
9191 the read-only transaction is semantically the same, and only indicates that the read-only transaction
9292 should end a that a new one should be started when the next statement is executed.
9393
94+ :type retry_aborts_internally: bool
95+ :param retry_aborts_internally:
96+ (Optional) Default True. When True, the connection will automatically retry aborted
97+ transactions by replaying all statements and validating checksums of read results.
98+ This is the recommended setting for interactive use and ORMs like Django that build
99+ transactions incrementally through individual cursor.execute() calls.
100+
101+ Set to False when the application already implements its own transaction retry logic
102+ (e.g. by wrapping the entire transaction in a callable and re-invoking it on abort,
103+ similar to ``Session.run_in_transaction``). In this mode, ``Aborted`` errors from
104+ ``commit()`` will be raised directly as ``RetryAborted`` without entering the
105+ internal statement-replay loop. This avoids nested retry loops and the associated
106+ contention amplification under concurrent writes.
107+
108+ This is equivalent to ``RETRY_ABORTS_INTERNALLY`` in the Spanner JDBC driver.
109+
94110 **kwargs: Initial value for connection variables.
95111 """
96112
97- def __init__ (self , instance , database = None , read_only = False , ** kwargs ):
113+ def __init__ (
114+ self , instance , database = None , read_only = False , retry_aborts_internally = True , ** kwargs
115+ ):
98116 self ._instance = instance
99117 self ._database = database
100118 self ._ddl_statements = []
@@ -110,6 +128,7 @@ def __init__(self, instance, database=None, read_only=False, **kwargs):
110128 # connection close
111129 self ._own_pool = True
112130 self ._read_only = read_only
131+ self ._retry_aborts_internally = retry_aborts_internally
113132 self ._staleness = None
114133 self .request_priority = None
115134 self ._transaction_begin_marked = False
@@ -248,6 +267,33 @@ def read_only(self, value):
248267 )
249268 self ._read_only = value
250269
270+ @property
271+ def retry_aborts_internally (self ):
272+ """Flag: whether the connection retries aborted transactions internally.
273+
274+ Returns:
275+ bool:
276+ True if the connection will retry aborted transactions using
277+ statement replay with checksum validation (default). False if
278+ aborted transactions will raise ``RetryAborted`` directly.
279+ """
280+ return self ._retry_aborts_internally
281+
282+ @retry_aborts_internally .setter
283+ def retry_aborts_internally (self , value ):
284+ """``retry_aborts_internally`` flag setter.
285+
286+ Args:
287+ value (bool): True to enable internal retry (default), False to disable.
288+ """
289+ if self ._spanner_transaction_started :
290+ raise ValueError (
291+ "retry_aborts_internally can't be changed while a transaction "
292+ "is in progress. Commit or rollback the current transaction "
293+ "and try again."
294+ )
295+ self ._retry_aborts_internally = value
296+
251297 @property
252298 def request_options (self ):
253299 """Options for the next SQL operations.
@@ -491,9 +537,12 @@ def commit(self):
491537 try :
492538 if self ._spanner_transaction_started and not self ._read_only :
493539 self ._transaction .commit ()
494- except Aborted :
495- self ._transaction_helper .retry_transaction ()
496- self .commit ()
540+ except Aborted as exc :
541+ if self ._retry_aborts_internally :
542+ self ._transaction_helper .retry_transaction ()
543+ self .commit ()
544+ else :
545+ raise RetryAborted (str (exc )) from exc
497546 finally :
498547 self ._reset_post_commit_or_rollback ()
499548
@@ -747,6 +796,7 @@ def connect(
747796 ca_certificate = None ,
748797 client_certificate = None ,
749798 client_key = None ,
799+ retry_aborts_internally = True ,
750800 ** kwargs ,
751801):
752802 """Creates a connection to a Google Cloud Spanner database.
@@ -822,6 +872,13 @@ def connect(
822872 :param client_key: (Optional) The path to the client key file used for mTLS connection.
823873 This is intended only for experimental host spanner endpoints.
824874 This is mandatory if the experimental_host requires an mTLS connection.
875+
876+ :type retry_aborts_internally: bool
877+ :param retry_aborts_internally:
878+ (Optional) Default True. When True, the connection will automatically retry
879+ aborted transactions internally by replaying all statements and validating
880+ checksums. Set to False when the application manages its own transaction retry
881+ logic. See ``Connection.retry_aborts_internally`` for details.
825882 """
826883 if client is None :
827884 client_info = ClientInfo (
@@ -866,7 +923,12 @@ def connect(
866923 database = instance .database (
867924 database_id , pool = pool , database_role = database_role , logger = logger
868925 )
869- conn = Connection (instance , database , ** kwargs )
926+ conn = Connection (
927+ instance ,
928+ database ,
929+ retry_aborts_internally = retry_aborts_internally ,
930+ ** kwargs ,
931+ )
870932 if pool is not None :
871933 conn ._own_pool = False
872934
0 commit comments