监控不同应用程序的MySQL插入

我目前有一个web服务,它使用Hibernate在mysql数据库中插入信息。 其中一些信息需要由另一个“导入”应用程序处理。 我不想从Web服务触发此应用程序。 因此,Web服务不依赖于Web服务,反之亦然。

有没有办法从“导入”应用程序“监听”数据库中的更改(特别是:插入),然后开始执行操作。 我看过触发器,但这些似乎只适用于应用程序的Hibernate Session中的更改而不适用于“外部”更改。

编辑*

简而言之,我想要的答案; 是否可以监视来自java应用程序的mysql数据库/表(来自任何源)的更改,该应用程序不会更改数据库/表本身

赏金更新*

我将奖励那些可以向我解释如何使用Java应用程序监视对MySQL表/数据库所做更改的人。 监视更改的Java应用程序不是应用任何更改的应用程序。 改变的来源可以是任何东西。

你可以阅读mysql二进制日志 。 在这里您可以找到一些信息 。 有一个java解析器和另一个 – 但它被标记为未完成)你也可以使用其他语言(例如, perl )查找类似的解析器,并用Java重写它们。
另外看看mysql-proxy 。

我认为你可以相当容易地实现这样的事情,假设你不介意在你的数据库上创建一些额外的表和触发器,并且监视java应用程序必须轮询数据库而不是专门接收触发器。

假设您要监视的表是这样的:

 CREATE TABLE ToMonitor ( id INTEGER PRIMARY KEY, value TEXT ); 

然后创建一个表来跟踪更改,并创建一个填充该表的触发器:

 CREATE TABLE InsertedRecords( value TEXT ); CREATE TRIGGER trig AFTER INSERT ON account FOR EACH ROW INSERT INTO InsertedRecords( value ) VALUES ( NEW.value ); 

这将导致InsertedRecords表填充ToMonitor中发生的每个插入。

然后你只需要设置你的监控应用程序定期SELECT * from InsertedRecords ,采取适当的行动,然后清除InsertedRecords的记录

编辑:一个轻微的替代方案,如果您不介意一些C / C ++编码,将按照此处的说明创建一个自定义SQL函数,触发您的监视应用程序的操作,然后从内部调用该SQL函数你创建的触发器。

我知道这不是你问的问题(因此,这不是一个正确的答案),但如果你考虑放弃“让数据库通知应用程序”的想法,你就可以得到使用JMS进行应用程序之间通信的完美案例。

发起更改的应用程序可以将消息发布到JMS主题,该主题由第二个应用程序订阅。 第一次更改数据库后,它会在主题上添加一条消息。 然后第二个看到这个新事件并采取相应行动。 您甚至可以在消息中发布增量,以便第二个应用程序不需要访问数据库。

我有点反对通过“黑客攻击”数据库而不仅仅是存储数据来解决这个问题,因为它将来不可避免地会遇到麻烦(因为最终会发生一切),调试它会很困难。 想象一下,在生态系统中添加第三个应用程序,你现在可以复制你为第二个应用程序所做的任何事情,但现在是第三个应用程序。 如果您没有记录您的步骤,您可能会迷路。

如果您只是在这两个应用程序之间使用JMS服务器,那么您当然可以在将来添加第三个应用程序,只需监听此主题(并发布新消息,以防它具有对数据库的写入权限),以及其他应用程序甚至不必知道还有一个应用程序。 也不是数据库。

假设我们要监视表’table1’中的更改

 CREATE TABLE `table1` ( `id` INT(10) NOT NULL AUTO_INCREMENT, `value` VARCHAR(50) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COLLATE='latin1_swedish_ci' ENGINE=InnoDB AUTO_INCREMENT=10; 

上面是创建’table1’的查询,它包含一个’id’列,它是自动增量

创建另一个表来存储更改。 查询如下

 CREATE TABLE `changes` ( `id` INT(10) NOT NULL AUTO_INCREMENT, `changes` VARCHAR(200) NULL DEFAULT '0', `change_time` TIMESTAMP NULL DEFAULT NULL, `tablename` VARCHAR(50) NULL DEFAULT NULL, `changed_id` VARCHAR(10) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COLLATE='latin1_swedish_ci' ENGINE=InnoDB AUTO_INCREMENT=21; 

现在在第一个表中创建一个触发器,即..’table1’查询如下

 delimiter | create trigger trg_table1 AFTER INSERT ON table1 FOR EACH ROW BEGIN DECLARE lastid INT DEFAULT 0; SELECT max(id) INTO lastid from table1; insert into changes values(null,'insert',now(),'table1',lastid); end; | delimiter ; 

现在,如果您尝试在“table1”中插入任何内容,其详细信息将自动插入到更改表中。 在更改表中,更改表示更改的类型,即插入,更新等,change_time表示发生更改的时间tablename表示发生更改的表changed_id表示“table1”中新插入的行的ID

现在创建一个连续读取“更改”表的java程序。 “更改”表中的新条目意味着数据库发生了某些事情。 从“更改”表中的每个记录中,您可以了解插入操作发生在哪个表中。 在此基础上,您可以执行适当的操作。 执行适当的操作后,从“更改”表中删除该行。

您可以为数据库中的每个表创建触发器(就像我上面所做的那样)…从’changes’表的’tablename’列中你可以理解插入发生在哪个表中..

您可以使用像Q4M这样的排队解决方案,但在您的情况下可能会有点过分。 但你可以:

在MySQL数据库中,将时间戳列添加到要插入的表中。 在’import’应用程序中,要么使用java.util.timer,要么使用外部调度程序,如cron。 使用其中一个来触发读取时间戳列为空的插入表的任务。 对这些行执行适当的操作,然后使用值设置timestamp列。 如果没有带空时间戳的行,则表示没有新插入。 简单,但它的工作原理。

出于性能原因,您可能希望为时间戳列添加索引。