Skip to content

Instantly share code, notes, and snippets.

@ryankask
Forked from carljm/db.py
Last active August 29, 2015 14:02
Show Gist options
  • Select an option

  • Save ryankask/a07662002b738d60e98f to your computer and use it in GitHub Desktop.

Select an option

Save ryankask/a07662002b738d60e98f to your computer and use it in GitHub Desktop.
"""
SQLAlchemy, PostgreSQL, and autocommit
The goal: DB-level autocommit by default. No unnecessary transaction around reads. Explicit transactions (and nested transactions using savepoints) when desired.
The below seems to achieve that, though I'm not very good at SQLAlchemy so it might be terrible.
"""
from contextlib import contextmanager
from sqlalchemy import create_engine, event
from sqlalchemy.orm import sessionmaker, Session as BaseSession
class Session(BaseSession):
def __init__(self, *a, **kw):
super(Session, self).__init__(*a, **kw)
self._in_atomic = False
@contextmanager
def atomic(self):
"""Transaction context manager.
Will commit the transaction on successful completion of the block, or
roll it back on error.
Supports nested usage (via savepoints).
"""
outer = not self._in_atomic
if outer:
self.begin()
self._in_atomic = True
else:
self.begin_nested()
try:
yield
except:
self.rollback()
raise
else:
self.commit()
finally:
if outer:
self._in_atomic = False
def xadd(self, *objs):
with self.atomic():
for obj in objs:
self.add(obj)
def is_deleted(self, obj):
obj_id = obj.id
self.expire(obj)
return self.query(type(obj)).get(obj_id) is None
class Database(object):
def __init__(self, db_uri):
self.engine = create_engine(db_uri, isolation_level="AUTOCOMMIT")
self.Session = sessionmaker(
bind=self.engine, class_=Session, autocommit=True)
@event.listens_for(self.Session, 'after_begin')
def receive_after_begin(session, transaction, connection):
self.engine.dialect._set_connection_isolation(
connection, 'READ COMMITTED')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment