Skip to content

DBAPI: transaction_checkout() uses explicit BeginTransaction RPC instead of inline begin #1503

@waiho-gumloop

Description

@waiho-gumloop

Environment details

  • OS: macOS (also reproducible on Linux)
  • Python version: 3.13.7
  • google-cloud-spanner version: 3.63.0
  • sqlalchemy-spanner version: 1.17.2

Problem

Connection.transaction_checkout() calls Transaction.begin() explicitly before the first query, which sends a standalone BeginTransaction gRPC RPC. This adds an unnecessary round-trip to every read-write transaction initiated through the DBAPI/SQLAlchemy path.

The Transaction class already supports inline begin — piggybacking BeginTransaction onto the first ExecuteSql request via TransactionSelector(begin=...). This is what Session.run_in_transaction() uses (it creates a Transaction without calling begin()). But the DBAPI's transaction_checkout() bypasses this by eagerly calling begin(), which sets _transaction_id before the first query and prevents the inline begin path in _make_txn_selector().

Current behavior (4 RPCs)

BeginTransaction → ExecuteSql (read) → ExecuteSql (write) → Commit

Expected behavior (3 RPCs)

ExecuteSql (read, with inline begin) → ExecuteSql (write) → Commit

Performance impact

Measured ~16ms overhead per transaction on the Spanner emulator. This affects every transaction_scope write operation when using the DBAPI or SQLAlchemy.

Root cause

Connection.transaction_checkout() calls self._transaction.begin() on L413. This was likely written before inline begin support was added to the Python client library. Inline begin landed in PR #740 (Dec 2022), but transaction_checkout was not updated to take advantage of it.

The fix is to remove the self._transaction.begin() call, letting execute_sql() / execute_update() / batch_update() use their existing inline begin logic via _make_txn_selector().

This is also fully conformant with PEP 249 (DB-API 2.0), which does not define a begin() method — transactions are implicit, and the mechanism by which the driver starts the server-side transaction is an implementation detail.

Proposed fix

Draft PR: #1502

Metadata

Metadata

Assignees

Labels

api: spannerIssues related to the googleapis/python-spanner API.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions