如何在 Java 中实现 db 侦听器

2022-08-31 13:52:14

我有一个要求,如果将记录插入到数据库表中,则自动需要执行java进程。实现数据库侦听器的最简单方法是什么?


答案 1

我有一个针对甲骨文的解决方案。您不需要创建自己的,因为现在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 子句或任何异常处理。


答案 2

类似的答案:如何使用java制作数据库监听器?

您可以使用支持事务的消息队列执行此操作,并在事务被委托时触发消息,或者(连接关闭)对于不支持通知的数据库。。在大多数情况下,您将必须手动通知并跟踪要通知的内容。

Spring为AMQPJMS提供了一些自动事务支持。您可以使用的一个更简单的替代方案是Guava的AsyncEventBus,但这仅适用于一个JVM。对于以下所有选项,我建议您使用消息队列通知平台的其余部分。

选项 - 非轮询非数据库特定

ORM 选项

Hibernate JPA这样的一些库具有实体侦听器,使这更容易,但这是因为它们假设它们管理所有CRUDing。

对于常规的JDBC,您必须自己记账。也就是说,在提交或关闭连接之后,然后向 MQ 发送消息,指出某些内容已更新。

JDBC 解析

簿记的一个复杂选择是包装/装饰您的和/或自定义的,以便在提交()(和关闭)时发送消息。我相信一些联合缓存系统会这样做。您可以捕获执行的SQL并进行解析,以查看它是INSERT还是UPDATE,但是如果没有非常复杂的解析和元数据,您将无法获得行级侦听。可悲的是,我不得不承认这是ORM提供的优势之一,因为它知道你的更新内容。java.sql.DataSourcejava.sql.Connection

道选项

如果您不使用ORM,最好的选择是在事务关闭后手动在DAO中发送一条消息,说明一行已经更新。只需确保在发送消息之前交易已关闭即可。

选项 - 轮询非数据库特定

在某种程度上遵循@GlenBest建议。

我有几件事我会以不同的方式做。我会将计时器外部化或使其只有一台服务器运行计时器(即调度程序)。我只会使用(最好将其包装在番石榴中)而不是Quartz(恕我直言,使用石英进行超级过度的投票)。ScheduledExecutorServiceListenerScheduledExecutorService

对于所有要观看的表格,您都应该添加一个“通知”列。

然后你做这样的事情:

// 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


推荐