在JDBC中一次执行多个语句

时间:2013-12-17 17:24:07

标签: java mysql 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(),这对于此线程不正确第二个帖子已经插入了一条记录 但是,这可以通过同步来克服。有没有办法在单个数据库调用中执行这两个语句?

4 个答案:

答案 0 :(得分:2)

LAST_INSERT_ID按连接工作,并且正如您的问题所述,如果两个线程中的两个语句使用相同的连接,则可能会出现竞争条件。

你有两种解决方法:

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

2:在同一API调用中使用executeUpdate getGeneratedKeys的形式,允许您稍后使用LAST_INSERT_ID进行阅读,这样您就不必使用{{ 1}}在第二个查询中,以避免竞争条件。您可以在准备好的陈述中使用类似的records the auto-generated key形式。

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

答案 1 :(得分:0)

根据https://dev.mysql.com/doc/refman/5.7/en/connector-j-reference-configuration-properties.html,您应该能够将?allowMultiQueries=true添加到JDBC连接字符串中。然后,您将能够在Statement#execute(String sql)调用中传递多个以分号分隔的语句。

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

答案 2 :(得分:0)

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

1)准备连接以使用multiquery: “JDBC:MySQL的://”, “?allowMultiQueries =真” +主机+ “/” +数据库+

2)将Insert Query与Select:

组合在一起

multiQuerySqlString =“INSERT INTO bug(summary,status,report_date)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();

我希望它有效

答案 3 :(得分:0)

如果 在一个连接上执行此操作,您可以要求驱动程序返回生成的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"});

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