2323from google .cloud .spanner_v1 import RequestOptions
2424from google .cloud .spanner_v1 .session import _get_retry_delay
2525from google .cloud .spanner_v1 .snapshot import Snapshot
26+ from deprecated import deprecated
2627
2728from google .cloud .spanner_dbapi .checksum import _compare_checksums
2829from google .cloud .spanner_dbapi .checksum import ResultsChecksum
3536
3637
3738CLIENT_TRANSACTION_NOT_STARTED_WARNING = (
38- "This method is non-operational as transaction has not started"
39+ "This method is non-operational as a transaction has not been started. "
3940)
4041MAX_INTERNAL_RETRIES = 50
4142
@@ -107,6 +108,9 @@ def __init__(self, instance, database=None, read_only=False):
107108 self ._staleness = None
108109 self .request_priority = None
109110 self ._transaction_begin_marked = False
111+ # whether transaction started at Spanner. This means that we had
112+ # made atleast one call to Spanner.
113+ self ._spanner_transaction_started = False
110114
111115 @property
112116 def autocommit (self ):
@@ -140,26 +144,15 @@ def database(self):
140144 return self ._database
141145
142146 @property
143- def _spanner_transaction_started (self ):
144- """Flag: whether transaction started at Spanner. This means that we had
145- made atleast one call to Spanner. Property client_transaction_started
146- would always be true if this is true as transaction has to start first
147- at clientside than at Spanner
148-
149- Returns:
150- bool: True if Spanner transaction started, False otherwise.
151- """
147+ @deprecated (
148+ reason = "This method is deprecated. Use _spanner_transaction_started field"
149+ )
150+ def inside_transaction (self ):
152151 return (
153152 self ._transaction
154153 and not self ._transaction .committed
155154 and not self ._transaction .rolled_back
156- ) or (self ._snapshot is not None )
157-
158- @property
159- def inside_transaction (self ):
160- """Deprecated property which won't be supported in future versions.
161- Please use spanner_transaction_started property instead."""
162- return self ._spanner_transaction_started
155+ )
163156
164157 @property
165158 def _client_transaction_started (self ):
@@ -277,7 +270,8 @@ def _release_session(self):
277270 """
278271 if self .database is None :
279272 raise ValueError ("Database needs to be passed for this operation" )
280- self .database ._pool .put (self ._session )
273+ if self ._session is not None :
274+ self .database ._pool .put (self ._session )
281275 self ._session = None
282276
283277 def retry_transaction (self ):
@@ -293,7 +287,7 @@ def retry_transaction(self):
293287 """
294288 attempt = 0
295289 while True :
296- self ._transaction = None
290+ self ._spanner_transaction_started = False
297291 attempt += 1
298292 if attempt > MAX_INTERNAL_RETRIES :
299293 raise
@@ -319,7 +313,6 @@ def _rerun_previous_statements(self):
319313 status , res = transaction .batch_update (statements )
320314
321315 if status .code == ABORTED :
322- self .connection ._transaction = None
323316 raise Aborted (status .details )
324317
325318 retried_checksum = ResultsChecksum ()
@@ -363,6 +356,8 @@ def transaction_checkout(self):
363356 if not self .read_only and self ._client_transaction_started :
364357 if not self ._spanner_transaction_started :
365358 self ._transaction = self ._session_checkout ().transaction ()
359+ self ._snapshot = None
360+ self ._spanner_transaction_started = True
366361 self ._transaction .begin ()
367362
368363 return self ._transaction
@@ -377,11 +372,13 @@ def snapshot_checkout(self):
377372 :returns: A Cloud Spanner snapshot object, ready to use.
378373 """
379374 if self .read_only and self ._client_transaction_started :
380- if not self ._snapshot :
375+ if not self ._spanner_transaction_started :
381376 self ._snapshot = Snapshot (
382377 self ._session_checkout (), multi_use = True , ** self .staleness
383378 )
379+ self ._transaction = None
384380 self ._snapshot .begin ()
381+ self ._spanner_transaction_started = True
385382
386383 return self ._snapshot
387384
@@ -391,7 +388,7 @@ def close(self):
391388 The connection will be unusable from this point forward. If the
392389 connection has an active transaction, it will be rolled back.
393390 """
394- if self ._spanner_transaction_started and not self .read_only :
391+ if self ._spanner_transaction_started and not self ._read_only :
395392 self ._transaction .rollback ()
396393
397394 if self ._own_pool and self .database :
@@ -405,13 +402,15 @@ def begin(self):
405402 Marks the transaction as started.
406403
407404 :raises: :class:`InterfaceError`: if this connection is closed.
408- :raises: :class:`OperationalError`: if there is an existing transaction that has begin or is running
405+ :raises: :class:`OperationalError`: if there is an existing transaction
406+ that has been started
409407 """
410408 if self ._transaction_begin_marked :
411409 raise OperationalError ("A transaction has already started" )
412410 if self ._spanner_transaction_started :
413411 raise OperationalError (
414- "Beginning a new transaction is not allowed when a transaction is already running"
412+ "Beginning a new transaction is not allowed when a transaction "
413+ "is already running"
415414 )
416415 self ._transaction_begin_marked = True
417416
@@ -430,41 +429,37 @@ def commit(self):
430429 return
431430
432431 self .run_prior_DDL_statements ()
433- if self ._spanner_transaction_started :
434- try :
435- if self .read_only :
436- self ._snapshot = None
437- else :
438- self ._transaction .commit ()
439-
440- self ._release_session ()
441- self ._statements = []
442- self ._transaction_begin_marked = False
443- except Aborted :
444- self .retry_transaction ()
445- self .commit ()
432+ try :
433+ if self ._spanner_transaction_started and not self ._read_only :
434+ self ._transaction .commit ()
435+ except Aborted :
436+ self .retry_transaction ()
437+ self .commit ()
438+ finally :
439+ self ._release_session ()
440+ self ._statements = []
441+ self ._transaction_begin_marked = False
442+ self ._spanner_transaction_started = False
446443
447444 def rollback (self ):
448445 """Rolls back any pending transaction.
449446
450447 This is a no-op if there is no active client transaction.
451448 """
452-
453449 if not self ._client_transaction_started :
454450 warnings .warn (
455451 CLIENT_TRANSACTION_NOT_STARTED_WARNING , UserWarning , stacklevel = 2
456452 )
457453 return
458454
459- if self ._spanner_transaction_started :
460- if self .read_only :
461- self ._snapshot = None
462- else :
455+ try :
456+ if self ._spanner_transaction_started and not self ._read_only :
463457 self ._transaction .rollback ()
464-
458+ finally :
465459 self ._release_session ()
466460 self ._statements = []
467461 self ._transaction_begin_marked = False
462+ self ._spanner_transaction_started = False
468463
469464 @check_not_closed
470465 def cursor (self ):
0 commit comments