转自:http://www.codexiu.cn/python/sqlalchemy基础教程/531/
5. SQLAlchemy会话与事务控制
5.1. 基本使用
SQLAlchemy 的 session 是用于管理数据库操作的一个像容器一样的东西. 模型实例对象本身独立存在, 而要让其修改(创建)生效, 则需要把它们加入某个 session . 同时你也可以把模型实例对象从 session 中去除. 被 session 管理的实例对象, 在 session.commit()
时被提交到数据库. 同时 session.rollback()
是回滚变更.
session.flush()
的作用是在事务管理内与数据库发生交互, 对应的实例状态被反映到数据库. 比如自增 ID 被填充上值.
user = User(name=u'名字') session.add(user) session.commit()
try: user = session.Query(User).first() user.name = u'改名字 session.commit() except: session.rollback()
5.2. for update
SQLAlchemy 的 Query 支持 select ... for update / share
.
session.Query(User).with_for_update().first() session.Query(User).with_for_update(read=True).first()
完整形式是:
with_for_update(read=False, nowait=False, of=None)
- read
-
是标识加互斥锁还是共享锁. 当为
True
时, 即for share
的语句, 是共享锁. 多个事务可以获取共享锁, 互斥锁只能一个事务获取. 有"多个地方"都希望是"这段时间我获取的数据不能被修改, 我也不会改", 那么只能使用共享锁. - nowait
- 其它事务碰到锁, 是否不等待直接"报错".
- of
- 指明上锁的表, 如果不指明, 则查询中涉及的所有表(行)都会加锁.
5.3. 事务嵌套
SQLAlchemy 中的事务嵌套有两种情况. 一是在 session 中管理的事务, 本身有层次性. 二是 session 和原始的 connection 之间, 是一种层次关系, 在这 session , connection 两个概念之中的事务同样具有这样的层次.
session 中的事务, 可能通过 begin_nested()
方法做 savepoint :
session.add(u1) session.add(u2) session.begin_nested() session.add(u3) session.rollback() # rolls back u3, keeps u1 and u2 session.commit()
或者使用上下文对象:
for record in records: try: with session.begin_nested(): session.merge(record) except: print "Skipped record %s" % record session.commit()
嵌套的事务的一个效果, 是最外层事务提交整个变更才会生效.
user = User(name='2') session.begin_nested() session.add(user) session.commit() session.rollback()
于是, 前面说的第二种情况有一种应用方式, 就是在 connection 上做一个事务, 最终也在 connection 上回滚这个事务, 如果 session 是 bind
到这个连接上的, 那么 session 上所做的更改全部不会生效:
conn = Engine.connect() session = Session(bind=conn) trans = conn.begin() user = User(name='2') session.begin_nested() session.add(user) session.commit() session.commit() trans.rollback()
在测试中这种方式可能会有用.
5.4. 二段式提交
二段式提交, Two-Phase, 是为解决分布式环境下多点事务控制的一套协议.
与一般事务控制的不同是, 一般事务是 begin
, 之后 commit
结束.
而二段式提交的流程上, begin
之后, 是 prepare transaction 'transaction_id'
, 这时相关事务数据已经持久化了. 之后, 再在任何时候(哪怕重启服务), 作 commit prepared 'transaction_id'
或者 rollback prepared 'transaction_id'
.
从多点事务的控制来看, 应用层要做的事是, 先把任务分发出去, 然后收集"事务准备"的状态(prepare transaction
的结果). 根据收集的结果决定最后是 commit 还是 rollback .
简单来说, 就是事务先保存, 再说提交的事.
SQLAlchemy 中对这个机制的支持, 是在构建会话类是加入 twophase
参数:
Session = sessionmaker(twophase=True)
然后会话类可以根据一些策略, 绑定多个 Engine , 可以是多个数据库连接, 比如:
Session = sessionmaker(twophase=True) Session.configure(binds={User: Engine, Blog: Engine2})
这样, 在获取一个会话实例之后, 就处在二段式提交机制的支持之下, SQLAlchemy 自己会作多点的协调了. 完整的流程:
Engine = create_engine('postgresql://test@localhost:5432/test', echo=True) Engine2 = create_engine('postgresql://test@localhost:5432/test2', echo=True) Session = sessionmaker(twophase=True) Session.configure(binds={User: Engine, Blog: Engine2}) session = Session() user = User(name=u'名字') session.add(user) session.commit()
对应的 SQL 大概就是:
begin; insert into "user" (name) values (?); prepare transaction 'xx'; commit prepared 'xx';
使用时, Postgresql 数据库需要把 max_prepared_transactions 这个配置项的值改成大于 0
5. SQLAlchemy会话与事务控制
5.1. 基本使用
SQLAlchemy 的 session 是用于管理数据库操作的一个像容器一样的东西. 模型实例对象本身独立存在, 而要让其修改(创建)生效, 则需要把它们加入某个 session . 同时你也可以把模型实例对象从 session 中去除. 被 session 管理的实例对象, 在 session.commit()
时被提交到数据库. 同时 session.rollback()
是回滚变更.
session.flush()
的作用是在事务管理内与数据库发生交互, 对应的实例状态被反映到数据库. 比如自增 ID 被填充上值.
user = User(name=u'名字') session.add(user) session.commit()
try: user = session.Query(User).first() user.name = u'改名字 session.commit() except: session.rollback()
5.2. for update
SQLAlchemy 的 Query 支持 select ... for update / share
.
session.Query(User).with_for_update().first() session.Query(User).with_for_update(read=True).first()
完整形式是:
with_for_update(read=False, nowait=False, of=None)
- read
-
是标识加互斥锁还是共享锁. 当为
True
时, 即for share
的语句, 是共享锁. 多个事务可以获取共享锁, 互斥锁只能一个事务获取. 有"多个地方"都希望是"这段时间我获取的数据不能被修改, 我也不会改", 那么只能使用共享锁. - nowait
- 其它事务碰到锁, 是否不等待直接"报错".
- of
- 指明上锁的表, 如果不指明, 则查询中涉及的所有表(行)都会加锁.
5.3. 事务嵌套
SQLAlchemy 中的事务嵌套有两种情况. 一是在 session 中管理的事务, 本身有层次性. 二是 session 和原始的 connection 之间, 是一种层次关系, 在这 session , connection 两个概念之中的事务同样具有这样的层次.
session 中的事务, 可能通过 begin_nested()
方法做 savepoint :
session.add(u1) session.add(u2) session.begin_nested() session.add(u3) session.rollback() # rolls back u3, keeps u1 and u2 session.commit()
或者使用上下文对象:
for record in records: try: with session.begin_nested(): session.merge(record) except: print "Skipped record %s" % record session.commit()
嵌套的事务的一个效果, 是最外层事务提交整个变更才会生效.
user = User(name='2') session.begin_nested() session.add(user) session.commit() session.rollback()
于是, 前面说的第二种情况有一种应用方式, 就是在 connection 上做一个事务, 最终也在 connection 上回滚这个事务, 如果 session 是 bind
到这个连接上的, 那么 session 上所做的更改全部不会生效:
conn = Engine.connect() session = Session(bind=conn) trans = conn.begin() user = User(name='2') session.begin_nested() session.add(user) session.commit() session.commit() trans.rollback()
在测试中这种方式可能会有用.
5.4. 二段式提交
二段式提交, Two-Phase, 是为解决分布式环境下多点事务控制的一套协议.
与一般事务控制的不同是, 一般事务是 begin
, 之后 commit
结束.
而二段式提交的流程上, begin
之后, 是 prepare transaction 'transaction_id'
, 这时相关事务数据已经持久化了. 之后, 再在任何时候(哪怕重启服务), 作 commit prepared 'transaction_id'
或者 rollback prepared 'transaction_id'
.
从多点事务的控制来看, 应用层要做的事是, 先把任务分发出去, 然后收集"事务准备"的状态(prepare transaction
的结果). 根据收集的结果决定最后是 commit 还是 rollback .
简单来说, 就是事务先保存, 再说提交的事.
SQLAlchemy 中对这个机制的支持, 是在构建会话类是加入 twophase
参数:
Session = sessionmaker(twophase=True)
然后会话类可以根据一些策略, 绑定多个 Engine , 可以是多个数据库连接, 比如:
Session = sessionmaker(twophase=True) Session.configure(binds={User: Engine, Blog: Engine2})
这样, 在获取一个会话实例之后, 就处在二段式提交机制的支持之下, SQLAlchemy 自己会作多点的协调了. 完整的流程:
Engine = create_engine('postgresql://test@localhost:5432/test', echo=True) Engine2 = create_engine('postgresql://test@localhost:5432/test2', echo=True) Session = sessionmaker(twophase=True) Session.configure(binds={User: Engine, Blog: Engine2}) session = Session() user = User(name=u'名字') session.add(user) session.commit()
对应的 SQL 大概就是:
begin; insert into "user" (name) values (?); prepare transaction 'xx'; commit prepared 'xx';
使用时, Postgresql 数据库需要把 max_prepared_transactions 这个配置项的值改成大于 0