Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在JDBC中一次执行多条语句_Java_Mysql_Jdbc - Fatal编程技术网

Java 在JDBC中一次执行多条语句

Java 在JDBC中一次执行多条语句,java,mysql,jdbc,Java,Mysql,Jdbc,我正在使用MySQL数据库。下面的代码创建一条记录并从创建的记录中获取id: insertStmt = connection .prepareStatement("INSERT INTO bugs (summary, status, report_date) VALUES (?, ?, ? )"); //... insertStmt.executeUpdate(); idQuery = connection

我正在使用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\u INSERT\u ID
对每个连接都有效,正如您的问题所述,如果两个线程中的两条语句使用相同的连接,您可能会遇到竞争条件

有两种方法可以解决这个问题:

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

2:使用同一API调用中的
executeUpdate
格式,允许您稍后使用
getGeneratedKeys
读回,这样您就不必在第二次查询中使用
LAST\u INSERT\u ID
,从而避免竞争条件。在准备好的语句中也可以使用类似的形式

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

根据,您应该能够向JDBC连接字符串中添加
?allowMultiQueries=true
。然后,您将能够在
Statement\execute(stringsql)
调用中传递多个由分号分隔的语句


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

您可以尝试使用多重查询,将Insert和Select Last\u Insert\u ID()组合在同一个字符串中

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

2) 将Insert查询与Select组合:

multiQuerySqlString=“插入bug(摘要、状态、报告日期)值(1、2、3);选择上次插入ID()

3) e执行查询并期望多个结果集:

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"});

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

这两个线程将需要使用两个不同的连接—如果要分离事务,这是必需的。如果它们使用不同的连接,也没有问题。即使有不同的连接,插入也会在同一个表中,因此可能存在不一致。不,不会有任何不一致,因为数据库会确保您没有。链接到的executeUpdate()语句不会返回生成的键。它返回行计数或0。这很有用。在这个方法中使用PreparedStatement有一个限制,我实际上想使用它,因为它们更快更好。您可以在
prepareStatement
调用中使用类似的技术:您应该避免同时与多个线程共享一个连接。每个线程使用连接是正确的方法。同样,MySQL连接器/J驱动程序实际上使用
LAST\u INSERT\u ID()
本身执行一个单独的查询。因此,当多个线程使用同一个连接时,仍有可能出现争用情况。