我们有一个混合Web应用程序,使用collective.tin,collective.lead和SqlAlchemy将MySql数据库与Plone集成(最后升级到Plone 4.0)。
好的,我知道集体.tin从未被释放,集体。铅已被取代;然而,几年以来所有事情都(几乎)完美无缺。
最近我们遇到了一种非常奇怪的行为,并且正在寻求帮助以便理解它。
其中,我们有2个Plone内容类型,比如A和B,由子类化collective.tin和相应的innodb MySql表定义; B行有一个指向A的外键。
在15-20分钟的时间跨度内,2个不同的用户创建了3个A对象和10-20个B对象,这些对象未提交给MySql但被Plone索引;我用linux shell中的MySql客户端执行的查询无法找到那些A行(没有查找B行);但是,这两个用户以及其他用户通过Web应用程序(前面提到的组件堆栈)执行的查询偶尔仍然可以找到并正确地显示这些3A对象中的一些。
只有在我重新启动Zope实例后,才有可能从Plone Web界面恢复正常活动; 3 MySql数据库中仍然缺少行和许多B行,但是自动增量计数器显示了预期的增量;我不得不从Plone索引中移除3个无效的A对象大脑(不用担心B对象)。
有关可能原因和如何调查问题的任何建议吗?
答案 0 :(得分:4)
我们遇到了与sqlalchemy 0.4完全相同的问题;会话将与实际的数据库内容不同步。在我们的案例中,问题有点掩盖,因为用户通过会话亲缘关系被发送到集群中的特定后端。如果亲和力突然消失,消息就会消失。确切的细节有点模糊,因为我无法找到我所采用的修复的正确(古代)修订历史。
从我可以从上下文中收集到的是,会话标识映射可以防止会话要求数据库获取之前检索的对象。因此,它不会在不同的会话中看到对这些对象所做的更改。
修复是在每次提交或回滚后在会话上调用.expire_all()
; SQLAlchemy 0.5及以上版本会自动执行此操作(autoexpire=True
会话,现在称为expire_on_commit
我相信),但是对于0.4,您需要注册SessionExtension
才能为您执行此操作。< / p>
幸运的是,我们也为此项目使用了collective.lead
,所以我的修复就是您的修复:
# The identity map should be flushed on commit.
# SQLAlchemy 0.5 does this properly, but in 0.4 we need to do this via
# a SesssionExtension.
from sqlalchemy import __version__
if __version__[:3] == '0.4':
from sqlalchemy.orm.session import SessionExtension
class ExpireAllSessionExtension(SessionExtension):
def after_commit(self, session):
"""Expire the identity-map on commit"""
session.expire_all()
def after_rollback(self, session):
"""Expire the identity-map on rollback"""
session.expire_all()
def installExtension():
# Patch collective.lead.database to let us install the extension
# on the session created there.
from collective.lead.database import Database
old_session = Database.session.fget
def session(self):
session = old_session(self)
if session.extension is None:
session.extension = ExpireAllSessionExtension()
return session
Database.session = property(session)
else:
def installExtension():
pass
定义映射器时,使用以下命令安装此扩展名:
from .sessionexpiration import installExtension
# Ensure that sessions get properly expired on commit and rollback.
installExtension()