You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ZEO/ZODB客户端实例间事务无法同步问题求助

ZEO/ZODB客户端事务不同步问题的解决方案

问题背景

多ZEO/ZODB客户端实例间存在事务无法实时同步的问题:一个客户端提交写入事务后,其他客户端无法立即看到更新,仅重启后能获取数据库最新状态。

最小复现示例

1. 启动ZEO服务器

执行命令:

runzeo -C zeo.conf

zeo.conf配置内容:

<zeo>
address 127.0.0.1:9999
</zeo>

<filestorage>
  path /path/to/testing.fs
</filestorage>

2. 客户端代码(employees.py)

import persistent
from ZODB import DB
import transaction
from ZEO.ClientStorage import ClientStorage

class Employees(persistent.Persistent):
    def __init__(self,name=None):
        self.name=name

def list_employees():
    return employees.keys()

def add_employee(name):
    if name != "" and name not in list_employees():
        employees[name] = Employees(name)
    root['employees'] = employees
    transaction.commit()

storage = ClientStorage(('localhost', 9999), server_sync = True)
db = DB(storage)
connection = db.open()
root = connection.root()

if "employees" not in root:
    root["employees"] = {}
employees=root["employees"]

while True:
    choice=input("Press:\n"
                 "'L' to list employees,\n"
                 "'A' to add an employee,\n"
                 "'Q' to quit: ")
    choice=choice.lower()

    if choice=="l":
        print(list_employees())

    elif choice=="a":
        name=input("Employee name: ")
        with transaction.manager:
            add_employee(name)

    elif choice=="q":
        break

观察到的行为

  • 未执行写入事务时,两个客户端执行L命令的结果一致
  • 单个客户端添加员工后,自身能显示最新数据,但另一个客户端执行L仍显示旧数据
  • 重启滞后的客户端后,可正确显示数据库最新状态

已尝试方法

  • 创建ClientStorage时设置server_sync = True,问题未解决
  • 设置cache_size = 0,问题仍存在

解决方案

问题根源在于ZODB的连接级缓存:每个客户端连接独立维护对象缓存,其他客户端的事务提交不会自动触发本地缓存刷新。以下是几种可行的解决方式:

方案1:读取前主动刷新缓存

修改list_employees函数,在读取数据前强制从服务器拉取最新状态:

def list_employees():
    # 刷新连接缓存
    connection.cacheRefresh()
    # 重新获取最新的employees对象
    global employees
    employees = root["employees"]
    return employees.keys()

方案2:执行读取操作前同步事务

修改L命令的处理逻辑,调用connection.sync()同步服务器最新事务状态,失效本地缓存中已被修改的对象:

if choice=="l":
    # 同步服务器最新事务
    connection.sync()
    # 重新获取employees对象
    employees = root["employees"]
    print(list_employees())

方案3:监听远程事务事件实现自动刷新

通过ZEO的事务事件监听机制,当服务器有新事务提交时自动刷新本地缓存,添加以下代码到客户端:

def invalidate_cache(event):
    # 远程事务提交时失效本地缓存
    connection.cacheInvalidate()

# 注册事务事件监听
import ZEO
ZEO.subscribe_to_transaction_events(storage, invalidate_cache)

关键原理说明

  • ZODB缓存为连接隔离设计,每个连接的缓存独立,默认不会主动同步其他连接的修改
  • server_sync=True仅确保客户端提交事务时与服务器同步,不影响读取操作的缓存逻辑
  • cache_size=0仅限制缓存容量,不会完全禁用缓存,仍会保留最近访问的对象

环境信息

  • 操作系统:Ubuntu 22.04.1 LTS
  • 依赖版本:ZEO5.4.0、ZODB5.8.0、Python==3.10.6

内容的提问来源于stack exchange,提问作者Inspired_Blue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:12:59