我有一个 Java Web 应用程序(WAR 部署到 Tomcat),它在内存中保存缓存 ( Map<Long,Widget>
)。我有一个 Postgres 数据库,其中包含 widgets
表:
widget_id | widget_name | widget_value
(INT) (VARCHAR 50) (INT)
到 Widget
之间的 O/R 映射POJO 和 widgets
表记录,我使用的是MyBatis。我想实现一个解决方案,只要 widgets
中的值,Java 缓存(Map)就会实时更新。表的变化。我可以有一个轮询组件,每隔 30 秒检查一次表,但轮询在这里感觉不是正确的解决方案。所以这就是我的建议:
- 编写一个调用存储过程的 Postgres 触发器 (
run_cache_updater()
) - 该过程依次运行 shell 脚本 (
run_cache_updater.sh
) - 脚本以 base-64 编码更改后的
widgets
记录,然后将编码记录 curl 到 HTTP URL - Java WAR 有一个 servlet 监听 cURL 并处理任何
HttpServletRequests
发送给它。它以 64 为基数对记录进行解码并以某种方式将其转换为Widget
POJO。 - 缓存 (
Map<Long,Widget>
) 已使用正确的键/值进行更新。
这个解决方案感觉很尴尬,所以我首先想知道 Java/Postgres 专家如何处理这种情况。在这里投票是否有更好/更简单的选择(我只是很固执吗?)是否还有我忽略的另一个/更好/更标准的解决方案?
如果没有,并且这个解决方案是将更改的记录从 Postgres 推送到应用程序层的标准方法,那么我对如何编写触发器、存储过程和 shell 脚本感到窒息,以便整个 widgets
记录被传递到 cURL 语句中。在此先感谢您的任何帮助。
最佳答案
我无法与 MyBatis 交谈,但我可以告诉你 PostgreSQL 有一个内置的发布/订阅系统,这可以让你用更少的黑客技术来做到这一点。
首先,在小部件
上设置一个触发器,该触发器在每次插入、更新和删除操作时运行。让它提取主键和 NOTIFY
widgets_changed,id
。 (好吧,在 PL/pgSQL 中,您可能需要PERFORM pg_notify(...)
。)如果事务提交,PostgreSQL 将广播您的通知,从而使通知和相应的数据都发生更改对其他连接可见。
在客户端中,您需要运行一个专用于保持此 map 最新的线程。它将连接到 PostgreSQL,LISTEN
widgets_changed
开始排队通知,SELECT * FROM widgets
填充 map ,并等待通知到达。 (显然检查通知 involves polling the JDBC driver ,这很糟糕,但没有您想象的那么糟糕。有关具体实现,请参阅 PgNotificationPoller 。)看到通知后,查找指示的记录并更新您的 map 。请注意,在初始 SELECT *
之前进行 LISTEN
非常重要,因为记录可能在 SELECT *
和 LISTEN
之间更改.
此方法不需要 PostgreSQL 了解有关您的应用程序的任何信息。它所要做的就是发送通知;您的应用程序会完成剩下的工作。没有 shell 脚本,没有 HTTP,也没有回调,让您可以重新配置/重新部署应用程序,而无需重新配置数据库。它只是一个数据库,可以备份、恢复、复制等,没有额外的复杂性。同样,您的应用程序没有额外的复杂性:它所需要的只是与您已经拥有的 PostgreSQL 的连接。
关于java - Postgres 触发器更新 Java 缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13694778/