Skip to content

Commit 35d6ae4

Browse files
shanecarey17vir-mir
authored andcommitted
sqlalchemy adapter trx begin allow transaction_mode (#498)
* sqlalchemy adapter trx begin allow transaction_mode * adding tests
1 parent c761048 commit 35d6ae4

File tree

2 files changed

+82
-7
lines changed

2 files changed

+82
-7
lines changed

aiopg/sa/connection.py

+25-7
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,19 @@ def info(self):
134134
def connection(self):
135135
return self._connection
136136

137-
def begin(self):
137+
def begin(self, isolation_level=None, readonly=False, deferrable=False):
138138
"""Begin a transaction and return a transaction handle.
139139
140+
isolation_level - The isolation level of the transaction,
141+
should be one of 'SERIALIZABLE', 'REPEATABLE READ', 'READ COMMITTED',
142+
'READ UNCOMMITTED', default (None) is 'READ COMMITTED'
143+
144+
readonly - The transaction is read only
145+
146+
deferrable - The transaction may block when acquiring data before
147+
running without overhead of SERLIALIZABLE, has no effect unless
148+
transaction is both SERIALIZABLE and readonly
149+
140150
The returned object is an instance of Transaction. This
141151
object represents the "scope" of the transaction, which
142152
completes when either the .rollback or .commit method is
@@ -161,23 +171,31 @@ def begin(self):
161171
.begin_twophase - use a two phase/XA transaction
162172
163173
"""
164-
coro = self._begin()
174+
coro = self._begin(isolation_level, readonly, deferrable)
165175
return _TransactionContextManager(coro)
166176

167177
@asyncio.coroutine
168-
def _begin(self):
178+
def _begin(self, isolation_level, readonly, deferrable):
169179
if self._transaction is None:
170180
self._transaction = RootTransaction(self)
171-
yield from self._begin_impl()
181+
yield from self._begin_impl(isolation_level, readonly, deferrable)
172182
return self._transaction
173183
else:
174184
return Transaction(self, self._transaction)
175185

176186
@asyncio.coroutine
177-
def _begin_impl(self):
187+
def _begin_impl(self, isolation_level, readonly, deferrable):
188+
stmt = 'BEGIN'
189+
if isolation_level is not None:
190+
stmt += ' ISOLATION LEVEL ' + isolation_level
191+
if readonly:
192+
stmt += ' READ ONLY'
193+
if deferrable:
194+
stmt += ' DEFERRABLE'
195+
178196
cur = yield from self._connection.cursor()
179197
try:
180-
yield from cur.execute('BEGIN')
198+
yield from cur.execute(stmt)
181199
finally:
182200
cur.close()
183201

@@ -217,7 +235,7 @@ def begin_nested(self):
217235
def _begin_nested(self):
218236
if self._transaction is None:
219237
self._transaction = RootTransaction(self)
220-
yield from self._begin_impl()
238+
yield from self._begin_impl(None, False, False)
221239
else:
222240
self._transaction = NestedTransaction(self, self._transaction)
223241
self._transaction._savepoint = yield from self._savepoint_impl()

tests/test_sa_transaction.py

+57
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,60 @@ def test_transactions_sequence(xa_connect):
377377

378378
yield from tr3.commit()
379379
assert conn._transaction is None
380+
381+
382+
@asyncio.coroutine
383+
def test_transaction_mode(connect):
384+
conn = yield from connect()
385+
386+
yield from conn.execute(tbl.delete())
387+
388+
tr1 = yield from conn.begin(isolation_level='SERIALIZABLE')
389+
yield from conn.execute(tbl.insert().values(name='a'))
390+
res1 = yield from conn.scalar(tbl.count())
391+
assert 1 == res1
392+
yield from tr1.commit()
393+
394+
tr2 = yield from conn.begin(isolation_level='REPEATABLE READ')
395+
yield from conn.execute(tbl.insert().values(name='b'))
396+
res2 = yield from conn.scalar(tbl.count())
397+
assert 2 == res2
398+
yield from tr2.commit()
399+
400+
tr3 = yield from conn.begin(isolation_level='READ UNCOMMITTED')
401+
yield from conn.execute(tbl.insert().values(name='c'))
402+
res3 = yield from conn.scalar(tbl.count())
403+
assert 3 == res3
404+
yield from tr3.commit()
405+
406+
tr4 = yield from conn.begin(readonly=True)
407+
assert tr4 is conn._transaction
408+
res1 = yield from conn.scalar(tbl.count())
409+
assert 3 == res1
410+
yield from tr4.commit()
411+
412+
tr5 = yield from conn.begin(isolation_level='READ UNCOMMITTED',
413+
readonly=True)
414+
res1 = yield from conn.scalar(tbl.count())
415+
assert 3 == res1
416+
yield from tr5.commit()
417+
418+
tr6 = yield from conn.begin(deferrable=True)
419+
yield from conn.execute(tbl.insert().values(name='f'))
420+
res1 = yield from conn.scalar(tbl.count())
421+
assert 4 == res1
422+
yield from tr6.commit()
423+
424+
tr7 = yield from conn.begin(isolation_level='REPEATABLE READ',
425+
deferrable=True)
426+
yield from conn.execute(tbl.insert().values(name='g'))
427+
res1 = yield from conn.scalar(tbl.count())
428+
assert 5 == res1
429+
yield from tr7.commit()
430+
431+
tr8 = yield from conn.begin(isolation_level='SERIALIZABLE',
432+
readonly=True, deferrable=True)
433+
assert tr8 is conn._transaction
434+
res1 = yield from conn.scalar(tbl.count())
435+
assert 5 == res1
436+
yield from tr8.commit()

0 commit comments

Comments
 (0)