繁体   English   中英

在JDBC中一次执行多个语句

[英]Execute more than one statement at once in JDBC

我正在使用MySQL数据库。 下一段创建一条记录,并从创建的记录中获取ID:


    insertStmt = connection
                    .prepareStatement("INSERT INTO bugs (summary, status, report_date) VALUES (?, ?, ? )");
            //...
    insertStmt.executeUpdate();
    idQuery = connection.prepareStatement("SELECT LAST_INSERT_ID()");
    rs = idQuery.executeQuery();
    if (rs != null) {
                rs.next();
                return new Long(rs.getLong(1)).toString();
    }

现在,如果有两个线程执行此操作并交错执行,例如,第一个线程插入记录,然后由第二个线程插入,之后第一个线程调用last_insert_id(),此线程对于第二个线程而言是错误的已经插入了一条记录。
但是,使用同步可以解决此问题。 有没有办法可以在一个数据库调用中执行两个语句?

LAST_INSERT_ID每个连接有效,并且如您的问题所述,如果两个线程中的两个语句使用相同的连接,则可以具有竞争条件。

您有两种解决方法:

1:每个线程使用单独的连接(这并不容易,但这实际上是扩展和感知的最佳选择;使用连接池)

2:使用executeUpdate的形式在同一API调用中记录自动生成的密钥 ,使您以后可以使用getGeneratedKeys读取它,这样就不必在第二个查询中使用LAST_INSERT_ID ,从而避免了竞争情况。 您可以在准备好的语句中使用类似的prepareStatement形式。

选择2可能是短期内您想要的。 选项2中的链接直接指向该API。 此链接是MySQL文章,概述了如何使用它。

根据https://dev.mysql.com/doc/refman/5.7/zh-CN/connector-j-reference-configuration-properties.html ,您应该能够在JDBC连接字符串中添加?allowMultiQueries=true 这样,您就可以在Statement#execute(String sql)调用中传递多个由分号分隔的Statement#execute(String sql)

编辑:或使用执行所需操作的存储过程。 或者,正如您所说, synchronize Java代码。

您可以尝试使用Multiquery,将Insert和Select Last_INSERT_ID()组合在同一字符串中。

1)准备使用多重查询的连接:“ jdbc:mysql://” + host +“ /” + database +“?allowMultiQueries = true”

2)将插入查询与选择结合起来:

multiQuerySqlString =“将错误(摘要,状态,报告日期)插入VALUES(1、2、3); SELECT LAST_INSERT_ID()”

3)进行查询并期望有多个结果集:

boolean isResultSet = statement.execute();

ResultSet res = statement.getResultSet();

if isResultSet = statement.getMoreResults();

// Second ReulstSet object
res = cs.getResultSet();

我希望它能起作用

如果必须在单个连接上完成所有操作,则可以要求驱动程序返回生成的ID:

insertStmt = connection.prepareStatement("...",PreparedStatement.RETURN_GENERATED_KEYS );
insertStmt.executeUpdate();
ResultSet rs = insertStatement.getGeneratedKeys();
Long id = null;
if (rs != null) 
{
  rs.next();
  id = rs.getLong(1);
}
connection.commit();
return id;

根据驱动程序,您可能需要一个不同的prepareStatement()调用,该调用将列名作为第二个参数:

insertStmt = connection.prepareStatement("INSERT ", new String[] {"ID"});

但是即使使用上面的代码,您也应该在不同的物理连接上进行并发插入,以便能够正确地控制您的事务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM