我有一个使用session.merge()创建并定期更新的表行。如果DB(sqlite)中的表被删除,那么我得到一个ObjectDeletedError,但我找不到一种方法来优雅地处理它。
在异常时,我重新创建表,但异常仍然发生。
我需要做些什么才能让会话识别新表,创建行并像以前一样继续?
这是代码......
#!/usr/bin/env python
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
##============================================================================
class Module(Base):
"""Schema for the modules table."""
##------------------------------------------------------------------------
__tablename__ = "modules"
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
port = sqlalchemy.Column(sqlalchemy.Integer)
##------------------------------------------------------------------------
def __init__(self, id, port=None):
self.id = id
self.port = port
##============================================================================
class SessionMgr(object):
"""Class to manage the database session."""
##------------------------------------------------------------------------
def __init__(self, commitInterval=5, debug=False):
self.commitInterval = commitInterval
database = "merge-bug.db"
self.engine = sqlalchemy.create_engine("sqlite:///%s" % (database), echo=debug)
Session = sessionmaker(bind=self.engine)
self.session = Session()
self.create_tables()
##------------------------------------------------------------------------
def create_tables(self):
"""Create database tables if they do not exist."""
### List of tables to check/create.
tables = [ Module ]
### Create each table if it does not exist.
for t in tables:
tname = t.__tablename__
if not self.engine.dialect.has_table(self.engine.connect(), tname):
print "%s table didn't exist. Creating..." % (tname)
t.metadata.create_all(self.engine)
##------------------------------------------------------------------------
def commit(self):
"""Commit changes to the database."""
print "Committing to db"
try:
self.session.commit()
except Exception as ex:
print "ERROR: SessionMgr.commit():", ex
print "DEBUG: SessionMgr.commit(): Issuing a session rollback ..."
self.session.rollback()
## Check that tables still exist.
self.create_tables()
finally:
## Optional -- depends on use case.
#self.session.remove()
pass
##------------------------------------------------------------------------
##============================================================================
def main():
print "DEBUG: main():"
import time
sessmgr = SessionMgr(commitInterval=5, debug=False)
##
## Test adding a module and updating it using session.merge().
##
if 1:
errors = 0
m = Module(1234, 43210)
print "DEBUG: merge module"
mm = sessmgr.session.merge(m)
sessmgr.commit()
delay = 1
for i in range(10):
try:
print "DEBUG: sleeping %i second ..." % (delay)
time.sleep(delay)
port = mm.port + 1
print "DEBUG: updating port field to %i ..." % (port)
## Exception on the following statement if table is deleted !!
mm.port = port
sessmgr.commit()
print "DEBUG: updating id field ..."
mm.id = 1234
sessmgr.commit()
except Exception as ex:
print "DEBUG: caught exception", ex
if 0:
print "DEBUG: Issuing a session rollback ..."
sessmgr.session.rollback()
if 1:
print "DEBUG: Create tables ..."
sessmgr.create_tables()
if 1:
print "DEBUG: Remerge module ..."
m = Module(1234, 43210)
mm = sessmgr.session.merge(mm)
if 0:
print "DEBUG: Refresh merged module ..."
mm = sessmgr.session.merge(mm)
errors += 1
print "DEBUG: errors =", errors
if errors > 3:
raise
##============================================================================
if __name__ == "__main__":
main()
##============================================================================
这是输出......
DEBUG: main():
DEBUG: merge module
Committing to db
DEBUG: sleeping 2 second ...
DEBUG: updating port field to 43211 ...
Committing to db
DEBUG: updating id field ...
Committing to db
DEBUG: sleeping 2 second ...
DEBUG: caught exception (OperationalError) no such table: modules u'SELECT modules.id AS modules_id, modules.port AS modules_port \nFROM modules \nWHERE modules.id = ?' (1234,)
DEBUG: Create tables ...
modules table didn't exist. Creating...
Committing to db
DEBUG: Remerge module ...
DEBUG: errors = 1
DEBUG: sleeping 2 second ...
DEBUG: caught exception Instance '<Module at 0x102a586d0>' has been deleted, or its row is otherwise not present.
DEBUG: Create tables ...
Committing to db
DEBUG: Remerge module ...
DEBUG: errors = 2
DEBUG: sleeping 2 second ...
DEBUG: caught exception Instance '<Module at 0x102a586d0>' has been deleted, or its row is otherwise not present.
DEBUG: Create tables ...
Committing to db
DEBUG: Remerge module ...
DEBUG: errors = 3
DEBUG: sleeping 2 second ...
DEBUG: caught exception Instance '<Module at 0x102a586d0>' has been deleted, or its row is otherwise not present.
DEBUG: Create tables ...
Committing to db
DEBUG: Remerge module ...
DEBUG: errors = 4
Traceback (most recent call last):
File "merge_bug.py", line 135, in <module>
main()
File "merge_bug.py", line 103, in main
port = mm.port + 1
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/sqlalchemy/orm/attributes.py", line 316, in __get__
return self.impl.get(instance_state(instance), dict_)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/sqlalchemy/orm/attributes.py", line 611, in get
value = callable_(passive)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/sqlalchemy/orm/state.py", line 375, in __call__
self.manager.deferred_scalar_loader(self, toload)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/sqlalchemy/orm/loading.py", line 606, in load_scalar_attributes
raise orm_exc.ObjectDeletedError(state)
sqlalchemy.orm.exc.ObjectDeletedError: Instance '<Module at 0x102a586d0>' has been deleted, or its row is otherwise not present.
答案 0 :(得分:0)
我需要做些什么才能让会话识别新表,创建行并像以前一样继续?
当Session发生错误时,您需要将其回滚以取消当前事务:
session.rollback()
现在如果您仍然遇到此问题,那么SQLite可能无法处理被删除的表(我假设是通过不同的连接?)您可能需要完全重新连接到数据库 - 禁用连接池使用NullPool
将实现此目的,每次Session关闭其事务时,连接本身都将被关闭。
在应用程序运行时,关键数据库也不适合使用创建和删除表。如果需要删除表中的所有数据,请使用&#34; DELETE FROM table&#34;。应用程序运行时,表结构本身不应该更改(特别是在像SQLite这样的脆弱系统上)。