监视来自不同应用程序的MySQL插入

时间:2012-07-12 18:18:22

标签: java mysql hibernate

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

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

修改*

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

Bounty Update *

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

6 个答案:

答案 0 :(得分:11)

我认为你可以相当容易地实现这样的事情,假设你不介意创建一些额外的表格和在您的数据库上触发,并且监视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 ++编码,那么可以follow the instructions here创建一个自定义SQL函数来触发您的监控应用程序,然后只需调用它SQL函数来自您创建的触发器。

答案 1 :(得分:5)

您可以阅读mysql binary log。在这里你可以找到some information。有一个java parseranother one - 但它被标记为未完成)你也可以使用其他语言(例如perl)查找类似的解析器,并用Java重写它们。 /> 另请查看mysql-proxy

答案 2 :(得分:3)

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

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

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

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

答案 3 :(得分:3)

假设我们要监控表'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'列中你可以理解插入发生在哪个表中..

答案 4 :(得分:2)

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

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

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

答案 5 :(得分:1)

我猜这个答案还很晚,但是正如@dbf指出的那样,阅读 binlog 可能是一种方法。我建议调查Debezium's MySQL Connector


Debezium MySQL连接器读取binlog并产生更改 行级INSERT,UPDATE和DELETE操作和记录的事件 Kafka主题中的更改事件。

您的“另一个”应用程序然后可以阅读那些Kafka主题。