它有时发生在我的产品env上(大部分时间都可以).我怀疑它是否与sessionmaker func中的参数'expire_on_commit'有关
@close_session
def func():
session = DBSession() # scoped_session, thread_local
m = Model()
m.content = 'content'
session.add(m)
try:
session.commit()
except SQLAlchemyError as e:
session.rollback()
raise_my_exception()
return m.id
Run Code Online (Sandbox Code Playgroud)
close_session是一个装饰器,它将在'finally'部分中执行'DBSession().close()'.ObjectDeleteError发生在"return m.id"行中
SQLAlchemy配置:
engines = {
'master': create_engine(
settings.MASTER_URL, echo=settings.ECHO_SQL, pool_recycle=3600),
'slave': create_engine(
settings.SLAVE_URL, echo=settings.ECHO_SQL, pool_recycle=3600),
}
class RoutingSession(Session):
def get_bind(self, mapper=None, clause=None):
#return engines['master']
if self._flushing:
return engines['master']
else:
return engines['slave']
DBSession = scoped_session(sessionmaker(class_=RoutingSession))
Run Code Online (Sandbox Code Playgroud)
ObjectDeletedError文档:
class ObjectDeletedError(sqlalchemy.exc.InvalidRequestError)
| A refresh operation failed to retrieve the database
| row corresponding to an object's known primary key identity.
|
| A refresh operation proceeds when an expired attribute is
| accessed on an object, or when :meth:`.Query.get` is
| used to retrieve an object which is, upon retrieval, detected
| as expired. A SELECT is emitted for the target row
| based on primary key; if no row is returned, this
| exception is raised.
|
| The true meaning of this exception is simply that
| no row exists for the primary key identifier associated
| with a persistent object. The row may have been
| deleted, or in some cases the primary key updated
| to a new value, outside of the ORM's management of the target
| object.
|
Run Code Online (Sandbox Code Playgroud)
编辑:我在"session.commit()"之后放了"return m.id",仍然引发了ObjectDeletedEror
@close_session
def func():
session = DBSession() # scoped_session, thread_local
m = Model()
m.content = 'content'
session.add(m)
try:
session.commit()
return m.id
except SQLAlchemyError as e:
session.rollback()
raise_my_exception()
Run Code Online (Sandbox Code Playgroud)
EDIT2:
我更改了RoutingSession以仅返回master并且错误消失了:
class RoutingSession(Session):
def get_bind(self, mapper=None, clause=None):
return engines['master']
Run Code Online (Sandbox Code Playgroud)
所以它必须是与这个主/从配置相关的东西.
关于如何解决它的任何想法?
使用默认值(expire_on_commit = True)创建DBSession.所以在提交之后,当返回obj.id时,obj已经过期了.因此会话将从slave数据库(引擎['slave'])获取obj,但由于主从延迟,相应的记录尚未同步到slave.
此错误意味着以下两件事之一:
raise_my_exception() 实际上并没有引发异常,因此在 rollback() 期间,代码陷入“return m.id”并且该行不存在,因为它已回滚。
在您说 session.commit() 和“return m.id”之间,并发线程或进程正在删除该行。数据在提交后从“m”开始过期,因此下一次访问将从数据库中检索该对象的最新数据,并将其放入新事务中。这与您的描述“有时(大多数时候都可以)”是一致的。- 偶尔发生一次的问题通常是由于并发问题造成的。
| 归档时间: |
|
| 查看次数: |
2272 次 |
| 最近记录: |