14

假设我有两个或多个处理 SQLite 数据库的进程——一个“播放器”进程和许多“编辑器”进程。

“播放器”进程读取数据库并更新视图 - 在我的情况下,它将是根据存储在数据库中的事件混合到声卡的波形。

“编辑器”进程是该数据库的任何编辑器:它不断更改数据库。

现在我希望播放器能够快速反映编辑更改。

我知道 SQLite 提供挂钩来跟踪同一进程中的数据库更改,但似乎很少有关于如何使用多个进程执行此操作的信息。

我可以不断地轮询数据库,比较记录和触发事件,但这似乎效率很低,尤其是当数据库增长到很大时。

我正在考虑使用日志表和触发器,但我想知道是否有更简单的方法。

4

8 回答 8

4

关系数据库不是您最好的首选。

为什么?

您希望您的所有编辑器都将更改传递给您的播放器。

您的播放器实际上是所有这些编辑器的服务器。您的播放器需要多个打开的连接。它必须监听所有这些连接以进行更改。它必须显示这些更改。

如果更改非常大,您可以使用混合解决方案,编辑器会保留更改通知玩家。

无论哪种方式,编辑都必须通知他们的玩家他们有更改。这比玩家试图发现数据库中的变化要简单得多。


更好的设计是一个服务器,它接受来自编辑器的消息,持久化它们,并通知玩家。该服务器既不是编辑器也不是播放器,而只是一个确保所有消息都得到处理的代理。它接受来自编辑和播放器的连接。它管理数据库。

有两种实现。服务器是玩家。服务器与播放器是分开的。服务器的设计没有改变——只有协议。当服务器为播放器时,服务器直接调用播放器对象。当服务器与播放器分离时,服务器会写入播放器的套接字。

当播放器是服务器的一部分时,当从编辑器接收到消息时直接调用播放器对象。当播放器分离时,一个小型阅读器从套接字收集消息并调用播放器对象。

播放器连接到服务器,然后等待信息流。这可以是来自编辑器的输入,也可以是对服务器保存在数据库中的数据的引用。

如果您的消息流量足够小以至于网络延迟不成问题,编辑器会将所有数据发送到服务器/播放器。如果消息流量太大,则编辑器写入数据库并将仅包含数据库 FK 的消息发送到服务器/播放器。


请在您的问题中澄清“如果编辑器在通知时崩溃,则播放器会永久混乱”。

这听起来像是播放器服务的糟糕设计。除非它没有从各个编辑那里得到状态,否则它不能“永远搞砸”。如果它从编辑器获取状态(例如,但试图反映该状态),那么您应该考虑一种设计,玩家只需从编辑器获取状态并且不会“永久混乱”。

于 2009-03-24T11:55:22.550 回答
3

SQLite 有一个update_hook功能可以满足您的需求。

SQLite C 接口

数据更改通知回调

void *sqlite3_update_hook(
    sqlite3*,
    void(*)(void *,int ,char const *,char const *,sqlite3_int64),
    void*
);

sqlite3_update_hook()接口使用由第一个参数标识的数据库连接注册一个回调函数,每当在 rowid 表中更新、插入或删除行时将调用该回调函数。先前调用此函数为同一数据库连接设置的任何回调都将被覆盖。

不幸的是,Python sqlite 模块没有公开它......

这是一个稍微复杂的解决方法,它深入到 C api(来自 Python 代码)以利用它: https ://stackoverflow.com/a/16920926

于 2014-03-13T21:03:29.777 回答
2

只需在两个进程之间打开一个套接字,然后让编辑器告诉所有玩家有关更新的信息。

于 2009-03-24T11:40:26.547 回答
2

我认为在这种情况下,我会创建一个流程来管理数据库读/写。

每个想要对数据库进行一些修改的编辑器都会调用这个过程,无论是通过 IPC 还是网络,或者任何方法。

然后,此过程可以通知玩家数据库中的更改。玩家,当他想要检索一些数据时,应该向管理数据库的进程提出它想要的数据的请求。(或者 db 进程在通知更改时告诉它它需要什么,因此不需要来自玩家的请求)

这样做的好处是只有一个进程访问 SQLite DB,因此数据库上没有锁定或并发问题。

于 2009-03-24T12:45:44.410 回答
1

编辑:我假设同一台机器上的进程。

在我看来有两种方法:

  • 轮询(如您所述),但将其保留为单个值(例如仅保留其他表的 LastUpdateTime 的表)

  • 使用目标平台上可用的任何进程间通信。这可能是 Windows 中的事件(例如,在 C# 中(我不知道在 Python 中)ManualResetEvent、AutoResetEvent 或 Mutex,如果您想在每个进程中牺牲一个服务员线程),或者是 Linux 中的信号

于 2009-03-24T11:49:30.520 回答
1

如果它在同一台机器上,最简单的方法是命名管道、带有阻塞 read() 的“播放器”和“编辑器”在修改数据库时将令牌放入管道。

于 2009-03-24T11:56:09.410 回答
1

有多少编辑器进程(为什么是进程?),以及您期望多久更新一次?这听起来不是一个好的设计,尤其是考虑到 sqlite 真的对数据库的多个并发访问不太满意。

如果多个进程有意义并且您想要持久化,那么让编辑器通过套接字、管道、共享内存等通知您的播放器然后让播放器(也称为服务器进程)进行持久化可能会更聪明。

于 2009-03-24T12:30:20.763 回答
0

Sqlite 本身没有实现这一点的机制。我看到的最接近这个问题的特性是监控文件系统。有很多选择。Stackoverflow 对此进行了讨论:如何查看文件以进行更改?.

其他编程语言也有相同的讨论: 如何让我的程序监视 C++ 中的文件修改?

于 2021-11-01T14:29:20.487 回答