1

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.
4

1 に答える 1

0

セッションに新しいテーブルを認識させ、行を作成し、以前と同じように続行するにはどうすればよいですか??

セッションでエラーが発生した場合は、ロールバックして現在のトランザクションをキャンセルする必要があります。

session.rollback()

それでもこの問題が発生する場合は、SQLite が削除されたテーブルを処理できない可能性があります (別の接続によるものだと思いますか?)。データベースに完全に再接続する必要があるかもしれません。接続プールを無効NullPoolにすると、これが実現します。セッションがそのトランザクションを閉じるたびに、接続自体が閉じられます。

また、アプリケーションの実行中にテーブルを作成および削除するのは、リレーショナル データベースの適切な使用方法ではありません。テーブル内のすべてのデータを削除する必要がある場合は、「DELETE FROM テーブル」を使用します。アプリケーションの実行中 (特に SQLite のような壊れやすいシステムでは)、テーブル構造自体は変更されるべきではありません。

于 2013-06-17T05:40:02.853 に答える