【问题标题】:Why Java MySQL connection can't detect change that made by trigger?为什么 Java MySQL 连接无法检测到触发器所做的更改?
【发布时间】:2012-03-19 16:32:06
【问题描述】:

我有一个问题,需要一些启发..

我正在使用触发器来检测对我的数据库所做的更改,这意味着我为我的所有表设置了插入、更新和删除触发器 (MySQL)

然后我将该更改写入我专门制作的表格中,以包含有关更改的所有信息。我们将其命名为 xtable。 (此表不带触发器)

我的 Java 程序需要不断读取该 xtable 以让其他应用程序知道更改。

问题是,当我循环读取 xtable 时,我只能读取与数据库建立连接时的 xtable 初始值。 (连接在循环外建立)

如果对数据库进行了更改,这将导致 xtable 中的新行,则无论我通过执行“select * from xtable”查询读取多少次,都不会检测到由触发器生成的新行..

代码如下:

public static void main(String[] args) {
    Connection conn = null;

    try {
        conn = database.getConnection();
        Statement state = conn.createStatement();
        String query = "select * from `xtable`;";

        while (true) {
            ResultSet rs = state.executeQuery(query);

            while(rs.next){
                // Some code for letting the other application know of the change
            }
        }
    } catch (SQLException ex) {
    } finally {
        if (conn != null) {
            conn.close();
        }
    }
}

所以基本上如果我在 xtable 为空时运行程序,我总是会获得一个空的 ResultSet,即使有时之后有新行。

其实这个问题可以通过在循环内部建立连接来解决,但是这会导致另一个问题,因为随着循环的进行,它会消耗越来越多的资源。 (我已经尝试过了,有时即使我已经正确关闭它,它最终也会使用我计算机上的所有资源)

那么谁能给我一些建议怎么办?

这是我第一次在这里发问题,如果有一些我不遵守的规则,我很抱歉,请给我正确的方向。

【问题讨论】:

  • 这是一个非常糟糕的设计。考虑改用zeromq发布/订阅等消息队列系统。
  • 在内部 while 循环之后关闭 ResultSet。确保您的 Connection 使用 Connection.TRANSACTION_READ_COMMITTED 隔离级别,并像这样创建您的语句: state = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
  • 确保导致触发的代码是自动提交或者您明确提交了插入/更新。
  • @JimGarrison 你的意思是糟糕的设计你能更具体吗?这是否意味着我不应该使用触发器?如果不使用触发器,我应该如何检测数据库的变化?
  • @brettw 嘿,我只是试试你的建议,现在它奏效了!我认为问题是我没有指定任何事务隔离,然后默认情况下在这里可能不会发生幻读。我怀疑设置了范围锁,但我仍然不明白为什么如果是这种情况,触发器仍然可以写入表。感谢您的回答。如果可能的话,请向我解释正确的解释:)

标签: java mysql loops triggers database-connection


【解决方案1】:

有事务隔离之类的东西。您的连接可能没有看到更改,因为您没有提交来自触发器的事务,或者您没有在客户端启动新的事务。没有看到您的数据库设置就无法判断。

PS:消息队列是更好的选择

【讨论】:

  • 嗨,谢谢你的信息。我刚刚阅读了一些关于事务隔离的解释,看起来我还有一些研究要做。更新数据库的应用程序是 autoCommit,因为我没有指定任何内容。 @brettw 已经给了我解决方案,问题在于我在读取表格时没有指定任何事务隔离级别。所以我认为这里不允许幻读或类似的东西。顺便说一句,非常感谢您提到事务隔离,我真的从中学到了很多..
  • 哦,关于消息队列。您是要使用它作为触发器的替代品,还是只是为了让其他应用程序知道?我读过它,但我不明白它是如何替代触发器来检测数据库变化的..
【解决方案2】:

我认为您最好考虑触发而不是通过循环查询 DBMS。

如果您使用触发器,则不必使用 Java 端的“while”循环来检查数据库的变化。
相反,嵌入在 DBMS 中的触发机制会在发生更改时通知 Java 端。

对于 Oracle,您可以从 PL/SQL 调用 Java 方法。
对于 PostgreSQL,您可以从 PL/Java 调用 Java 方法。
对于 CUBRID,可以从 Java 存储过程中调用 Java 方法。

对于 MySQL,你可以调用 Java 方法,但我认为没有上面那么简单。
我希望这个链接能帮助你。 http://code.rocksol.it/call-java-from-mysql-trigger
或者google这个关键字,“mysql java用户定义函数”

【讨论】:

    【解决方案3】:
      Connection connection=getConnection();
      statement="query";
      try {
                stmt = connection.prepareStatement(statement);
                  ResultSet rs = stmt.executeQuery();
                while (rs.next()) {
    
            }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                if (connection != null && stmt != null) {
                    stmt.close();
                }
            }
    

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
    猜你喜欢
    • 2014-01-15
    • 1970-01-01
    • 2011-05-19
    • 2018-08-21
    • 2022-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多