sqlalchemy.orm.exc.DetachedInstanceError: Instanceis not bound to a Session; attribute refresh operation cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)

发布时间 2023-06-02 19:14:13作者: zjhgx

在使用sqlalchemy 的orm时,在一个循环中,如果一开始select时用了session,中间update某条记录后,session被关闭,就会出现对象not bound to a Session的问题.

 DBSession = sessionmaker(bind=self.engine,expire_on_commit=False)

这时需要 expire_on_commit=False

 

The most common reason that objects become detached from their Session is that the session itself was closed, typically via the Session.close() method. The objects will then live on to be accessed further, very often within web applications where they are delivered to a server-side templating engine and are asked for further attributes which they cannot load.

Mitigation of this error is via these techniques:

  • Try not to have detached objects; don’t close the session prematurely - Often, applications will close out a transaction before passing off related objects to some other system which then fails due to this error. Sometimes the transaction doesn’t need to be closed so soon; an example is the web application closes out the transaction before the view is rendered. This is often done in the name of “correctness”, but may be seen as a mis-application of “encapsulation”, as this term refers to code organization, not actual actions. The template that uses an ORM object is making use of the proxy pattern which keeps database logic encapsulated from the caller. If the Session can be held open until the lifespan of the objects are done, this is the best approach.

  • Otherwise, load everything that’s needed up front - It is very often impossible to keep the transaction open, especially in more complex applications that need to pass objects off to other systems that can’t run in the same context even though they’re in the same process. In this case, the application should prepare to deal with detached objects, and should try to make appropriate use of eager loading to ensure that objects have what they need up front.

  • And importantly, set expire_on_commit to False - When using detached objects, the most common reason objects need to re-load data is because they were expired from the last call to Session.commit(). This expiration should not be used when dealing with detached objects; so the Session.expire_on_commit parameter be set to False. By preventing the objects from becoming expired outside of the transaction, the data which was loaded will remain present and will not incur additional lazy loads when that data is accessed.

    Note also that Session.rollback() method unconditionally expires all contents in the Session and should also be avoided in non-error scenarios.