【问题标题】:Insert after Select (Java sql)选择后插入(Java sql)
【发布时间】:2018-03-20 07:44:46
【问题描述】:

挣扎于一些执行存储过程调用的java / sql代码,然后是select,然后是insert into -

对存储过程的调用起作用并创建了“持续时间”表——

while(true) {

  boolean var1 = false;
  Connection var2 = DBConnPool.getInstance().getConnection();
  Statement var3 = null;
  ResultSet var4 = null;

try {
     var3 = var2.createStatement();
     String var5;
     var5 = "CALL totalduration('%', NOW() - INTERVAL 20 MINUTE, NOW());";
     var3.executeQuery(var5);

然后select语句运行并正确输出多行——

var5 = "SELECT duration.name, zone, duration, asset.id as assetid, node.id as nodeid\n" +
        "FROM duration\n" +
        "inner join asset\n" +
        "on asset.name = duration.name\n" +
        "inner join node\n" +
        "on node.zonename = duration.zone\n" +
        "where Duration > '00:10:00'\n" +
        "and Zone = 'Reception'\n" +
        "group by duration.name DESC";
        var4 = var3.executeQuery(var5);

然后我想从生成的 ResultSet 中插入表数据,如果我使用以下内容,那么它只插入 1 行

 If (var4.next()) 
             {
                int var6 = var4.getInt("assetid");
                int var7 = var4.getInt("nodeid");
                String var8;
                var8 = "insert into alerts (ts, assetid, alerttypeid, nodeid, ack) values (now(), " + var6 + ", " + 11 + ", " + var7 + ", 0)";
                var3.executeUpdate(var8);
         }

因此,我假设以下内容会将插入应用到所有 ResultSet 行 –

while(var4.next()) 
         {
            int var6 = var4.getInt("assetid");
            int var7 = var4.getInt("nodeid");
            String var8;
var8 = "insert into alerts (ts, assetid, alerttypeid, nodeid, ack) values (now(), " + var6 + ", " + 11 + ", " + var7 + ", 0)";
            var3.executeUpdate(var8);
         }

但是错误'Operation not allowed after ResultSet closed'暗示var4被关闭了?

我显然在做一些愚蠢的事情,也许插入应该在选择之前,所以希望得到一些关于解决这个问题的“正确方法”的指导。

问候 活跃

【问题讨论】:

  • 当您有参数时,请始终使用 PreparedStatementTake a look
  • 为什么插入只发生一次而不是每一行?插入可能需要在选择之前,但我不确定语法是否正确。
  • 仅供参考:您应该为变量命名比var#更有用的名称

标签: java mysql


【解决方案1】:

JavaDoc from ResultSet :

当生成它的 Statement 对象关闭、重新执行或用于从多个结果序列中检索下一个结果时,ResultSet 对象会自动关闭。

您正在使用Statement var3 在循环中执行更新查询。由于这与用于恢复ResultSet var4Statement 相同,因此该实例将在下一个execute# 关闭。这就是为什么您能够读取第一行,执行更新,然后出现错误。

您需要使用不同的Statement 实例来保持ResultSet 处于打开状态。实际上,ResultSet 绑定到 Statement

注意:

  1. var# 不是变量的好名称,stmtrs、...是一些更合适的名称,并且无需搜索声明即可轻松理解每个实例的含义。

  2. 请注意,您还应该关闭 Statement, ResultSet, ... 当您完成它们时(即使出现异常)。在这里,我将在下面的示例中添加一个try-with-resource

  3. 使用 PreparedStament 而不是连接 String,这将更具可读性,并且在 String 值的情况下,这将更安全(针对 SQL 注入)

示例(对注释进行了一些改进):

try (PreparedStatement ps = conn.prepareStatement("insert into a(b, c) values (?, ?)") ) {
    while(var4.next()) {
        ps.setInt(1, rs.getInt("b"));
        ps.setInt(2, rs.getInt("c"));
        ps.executeUpdate();
    }
} catch( SQLException e){
    ...
}

【讨论】:

  • 感谢 AxelH,虽然我得到了 try-with-resources 在源 1.6 中不支持(使用 JDK1.6),但 1.6 是否有等效命令?
  • @active 你必须在finally 子句中自己做,按顺序检查实例是否为空,或者为每个(ResultSet、Statement、Connection)关闭它(使用try-catch)。在您的情况下,连接应该释放到池中。
  • 感谢 AxelH,您能否提供一个示例 finally 子句(我是新手)
  • 谢谢,我会尽力解决这个问题,尽管我可能需要在这方面获得一些外部帮助。这似乎过于复杂(对我而言)
  • @active 是什么? PreparedStatement 是一个特定的 Statement,您可以对其进行参数化,设置一次查询并即时设置参数以执行查询。如果你在这方面需要更多帮助,我建议你看看一些关于 JDBC 的教程。
猜你喜欢
  • 2023-03-27
  • 2014-10-26
  • 2014-10-05
  • 1970-01-01
  • 2015-08-03
  • 2014-10-17
  • 2017-05-29
  • 2014-10-17
  • 1970-01-01
相关资源
最近更新 更多