Sessions and transactions
Sessions are active connections to the database. A session can have multiple transactions as part of its lifecycle.
When using the engine object as a context, a session and a transaction are created. The transaction will be commited on context exit if no error are raised, rollbacked otherwise.
with engine as tx:
tx.execute("INSERT INTO ...")
# auto commited
with engine as tx:
tx.execute("INSERT INTO ...")
raise Exception()
# rollback
The next section covers how to use transactions.
Note
You can create transactions inside transactions with no impact (only the top-most transaction will commit)
with engine as tx:
tx.execute("INSERT INTO ...")
with engine as tx:
# ...
In most cases, using the engine as the context is the most straighforward method. However, in some circumstances you want to have an active session to be able to run select queries and eventually start transactions to perform modifications. This is a common use case in web applications.
with engine.session() as sess:
todos = Task.find_all(done=False)
with sess as tx:
Task.create(title="my task")
# commit
todos = Task.find_all(done=False)
# rollback
Warning
Session contexts are scoped to threads using thread locals.
This means that using drivers which are not thread-safe (like sqlite) is not an issue as long as you are using the engine
to start sessions. Doing with engine.session()
and with engine:
in different threads will start different sessions.
transaction()
can be used to create a transaction in the currently available session context
when the session context is not directly accessible:
from sqlorm import transaction
with engine.session():
with transaction() as tx:
Task.create(title="my task")
# commit
To ensure that a transaction is available, use ensure_transaction()
. This will ensure
a session is available and create a virtual transaction (ie. which neither commit or rollback).
from sqlorm import ensure_transaction
def count_tasks():
with ensure_transaction() as tx:
return tx.fetchscalar("SELECT COUNT(*) FROM tasks")
with engine:
c = count_tasks() # works
# commit
with engine.session():
c = count_tasks() # works
# rollback
count_tasks() # raises MissingEngineError
Tip
Session
can be created using raw DBAPI connection objects
from sqlorm import Session
import sqlite3
conn = sqlite3.connect(":memory:")
with Session(conn) as sess:
with sess as tx:
# ...