如何在 Java 中实现 db 侦听器
我有一个要求,如果将记录插入到数据库表中,则自动需要执行java进程。实现数据库侦听器的最简单方法是什么?
我有一个要求,如果将记录插入到数据库表中,则自动需要执行java进程。实现数据库侦听器的最简单方法是什么?
我有一个针对甲骨文的解决方案。您不需要创建自己的,因为现在Oracle购买了Java,它为它发布了一个监听器。据我所知,这在内部不使用轮询,而是将通知推送到Java端(可能基于某些触发器):
public interface oracle.jdbc.dcn.DatabaseChangeListener
extends java.util.EventListener {
void onDatabaseChangeNotification(oracle.jdbc.dcn.DatabaseChangeEvent arg0);
}
你可以像这样实现它(这只是一个示例):
public class DBListener implements DatabaseChangeListener {
private DbChangeNotification toNotify;
public BNSDBListener(DbChangeNotification toNotify) {
this.toNotify = toNotify;
}
@Override
public void onDatabaseChangeNotification(oracle.jdbc.dcn.DatabaseChangeEvent e) {
synchronized( toNotify ) {
try {
toNotify.notifyDBChangeEvent(e); //do sth
} catch (Exception ex) {
Util.logMessage(CLASSNAME, "onDatabaseChangeNotification",
"Errors on the notifying object.", true);
Util.printStackTrace(ex);
Util.systemExit();
}
}
}
}
编辑:
您可以使用以下类进行注册:oracle.jdbc.OracleConnectionWrapper
public class oracle.jdbc.OracleConnectionWrapper implements oracle.jdbc.OracleConnection {...}
假设您在某处创建了一个方法:
public void registerPushNotification(String sql) {
oracle.jdbc.driver.OracleConnection oracleConnection = ...;//connect to db
dbProperties.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS, "true");
dbProperties.setProperty(OracleConnection.DCN_QUERY_CHANGE_NOTIFICATION, "true");
//this is what does the actual registering on the db end
oracle.jdbc.dcn.DatabaseChangeRegistration dbChangeRegistration= oracleConnection.registerDatabaseChangeNotification(dbProperties);
//now you can add the listener created before my EDIT
listener = new DBListener(this);
dbChangeRegistration.addListener(listener);
//now you need to add whatever tables you want to monitor
Statement stmt = oracleConnection.createStatement();
//associate the statement with the registration:
((OracleStatement) stmt).setDatabaseChangeRegistration(dbChangeRegistration); //look up the documentation to this method [http://docs.oracle.com/cd/E11882_01/appdev.112/e13995/oracle/jdbc/OracleStatement.html#setDatabaseChangeRegistration_oracle_jdbc_dcn_DatabaseChangeRegistration_]
ResultSet rs = stmt.executeQuery(sql); //you have to execute the query to link it to the statement for it to be monitored
while (rs.next()) { ...do sth with the results if interested... }
//see what tables are being monitored
String[] tableNames = dbChangeRegistration.getTables();
for (int i = 0; i < tableNames.length; i++) {
System.out.println(tableNames[i] + " has been registered.");
}
rs.close();
stmt.close();
}
此示例不包括 try-catch 子句或任何异常处理。
类似的答案:如何使用java制作数据库监听器?
您可以使用支持事务的消息队列执行此操作,并在事务被委托时触发消息,或者(连接关闭)对于不支持通知的数据库。。在大多数情况下,您将必须手动通知并跟踪要通知的内容。
Spring为AMQP和JMS提供了一些自动事务支持。您可以使用的一个更简单的替代方案是Guava的AsyncEventBus,但这仅适用于一个JVM。对于以下所有选项,我建议您使用消息队列通知平台的其余部分。
ORM 选项
像Hibernate JPA这样的一些库具有实体侦听器,使这更容易,但这是因为它们假设它们管理所有CRUDing。
对于常规的JDBC,您必须自己记账。也就是说,在提交或关闭连接之后,然后向 MQ 发送消息,指出某些内容已更新。
JDBC 解析
簿记的一个复杂选择是包装/装饰您的和/或自定义的,以便在提交()(
和关闭)时发送消息。我相信一些联合缓存系统会这样做。您可以捕获执行的SQL并进行解析,以查看它是INSERT还是UPDATE,但是如果没有非常复杂的解析和元数据,您将无法获得行级侦听。可悲的是,我不得不承认这是ORM提供的优势之一,因为它知道你的更新内容。java.sql.DataSource
java.sql.Connection
道选项
如果您不使用ORM,最好的选择是在事务关闭后手动在DAO中发送一条消息,说明一行已经更新。只需确保在发送消息之前交易已关闭即可。
在某种程度上遵循@GlenBest建议。
我有几件事我会以不同的方式做。我会将计时器外部化或使其只有一台服务器运行计时器(即调度程序)。我只会使用(最好将其包装在番石榴中)而不是Quartz(恕我直言,使用石英进行超级过度的投票)。ScheduledExecutorService
ListenerScheduledExecutorService
对于所有要观看的表格,您都应该添加一个“通知”列。
然后你做这样的事情:
// BEGIN Transaction
List<String> ids = execute("SELECT id FROM table where notified = 'f'");
//If db not transactional either insert ids in a tmp table or use IN clause
execute("update table set notified = 't' where notified = 'f'")
// COMMIT Transaction
for (String id : ids) { mq.sendMessage(table, id); }
使用Postgres,您仍然需要在某种程度上进行轮询,因此您将完成上述大部分操作,然后将消息发送到总线。NOTIFY