kun*_*unl 0 python session sqlalchemy peewee
我们有一个db.py定义了 peewee 数据库的文件:
db = PostgresqlExtDatabase('mom',
user=DB_CONFIG['username'],
password=DB_CONFIG['password'],
host=DB_CONFIG['host'],
port=DB_CONFIG['port'],
threadlocals=True,
register_hstore=False,
autocommit=True,
autorollback=True,
cursor_factory=DictCursor)
Run Code Online (Sandbox Code Playgroud)
调用db.execute("SOME RAW SQL UPDATE QUERY")按预期工作。但是begin在此之前调用 a并不会阻止数据库被修改。
db.begin()
db.execute("SOME RAW SQL UPDATE QUERY") # <- Does not wait, db is updated immediately here
db.commit()
Run Code Online (Sandbox Code Playgroud)
我这样做对吗?
如果一个事务已经在进行中,我基本上需要将原始 sql 嵌套在一个事务中,否则如果没有begin调用任何事务,则立即执行它。
这工作,如果我做的预期db.set_autocommit(False),然后execute_sql再commit()。
它也适用于atomic()上下文管理器。
给予一定的情况下,我工作的一个Web应用程序,物流,和我们的代码库使用瓶和SQLAlchemy的scoped_session使用autocommit设置为true。它不使用SQLAlchemy的ORM(因为..历史原因),而是只使用Session对象和它的
execute(),begin(),begin_nested(),rollback()和remove()方法。
它的实现方式是Session = scoped_session(sessionmaker(autocommit=True))在文件中定义一个 Session ,然后session = Session()在代码库中的任何地方调用,并使用session.execute("SQL")
有时session.begin()调用a来执行查询,因此在提交(或回滚)之前查询不会执行。
我们现在真的很想使用peewee。 但是.. 代码库是建立在这个会话上的。所以这必须被欺骗。去改变每个文件是不可能的,并且没有足够的测试用例来启动(出于......历史原因)。
我也有一些问题,但我不知道去哪里问,所以我希望你不介意我把它们放在这里:
这个 db 对象(及其连接)是否绑定到它正在执行的线程?如果 db 从两个不同的文件导入,并且db.begin()从每个文件中调用,基本上会出现一些错误吗?我可以在 ipython shell 中看到上面id的db对象对于每个线程都是相同的,所以我假设除非重新创建 psycopg2 连接,否则这应该被隔离吗?
为了欺骗 sqlalchemy Session,我创建了一个包装器类,它返回所需的会话类型、SQLASession对象或我为 peewee 编写的用于欺骗它的包装器。
class SessionMocker(object):
# DO NOT make this a singleton. Sessions will break
def __init__(self, orm_type=ORM_TYPES.SQLA):
assert orm_type in ORM_TYPES, "Invalid session constructor type"
super(SessionMocker, self).__init__()
self.orm_type = orm_type
def __call__(self, *args, **kwargs):
if self.orm_type == ORM_TYPES.SQLA:
return SQLASession(*args, **kwargs)
if self.orm_type == ORM_TYPES.PEEWEE:
# For now lets assume no slave
return SessionWrapper(*args, **kwargs)
raise NotImplementedError
def __getattr__(self, item):
"""
Assuming this will never be called without calling Session() first.
Else there is no way to tell what type of Session class (ORM) is required, since that can't be passed.
"""
if self.orm_type == ORM_TYPES.SQLA:
kls = SQLASession
elif self.orm_type == ORM_TYPES.PEEWEE:
kls = SessionWrapper
else:
raise NotImplementedError
return getattr(kls, item)
Session = SessionMocker(ORM_TYPES.SQLA)
Run Code Online (Sandbox Code Playgroud)我认为这将使代码库能够透明且无缝地切换到使用 peewee,而无需在任何地方更改它。我怎样才能以更好的方式做到这一点?
文档解释了如何执行此操作:http : //docs.peewee-orm.com/en/latest/peewee/transactions.html#autocommit-mode
但是,tl; dr,您需要在开始/提交/回滚之前禁用自动提交,才能像您期望的那样工作:
db.set_autocommit(False)
db.begin()
try:
user.delete_instance(recursive=True)
except:
db.rollback()
raise
else:
try:
db.commit()
except:
db.rollback()
raise
finally:
db.set_autocommit(True)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3298 次 |
| 最近记录: |