我可以从一个线程调用executeBacth而另一个在同一个Statement(或PreparedStatement)对象上继续调用addBatch()吗?
更新:有没有人对这个问题有所了解?因为我的结果不正确。并非我添加到批处理中的所有更新都已执行。
答案 0 :(得分:17)
我会退后一步,深深地重新考虑设计。为什么你想在两个线程之间共享相同的Statement
(因此也隐含在Connection
)?
正常的JDBC实践是,您应该获取并关闭最短可能范围内的Connection
,Statement
和ResultSet
。也就是说,在同一个方法块内。这是一个基本的例子:
public void update(List<Item> items) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = database.getConnection();
statement = connection.prepareStatement(sql);
for (Item item : items) {
statement.setObject(1, item.getSomething());
statement.addBatch();
}
statement.executeBatch();
} finally {
if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
}
如果您只想提高连接性能,请使用连接池。例如C3P0。但肯定不在线程之间共享昂贵的数据库资源!这样您也不必担心线程安全。这是一个实现细节。
哦,如果还不清楚:您将 通过在多个线程之间共享相同的语句和连接来提高数据库性能。更糟糕的是,它只会减速,你会遇到Java和数据库方面的线程安全问题。
答案 1 :(得分:6)
是。根据JDBC规范,所有JDBC驱动程序实现必须是线程安全的:
Compliance with the JDBC 3.0 API, section A.1.6
如果我理解你对BalusC的响应的正确评论,你将从一个Statement迭代ResultSet并同时在一个单独的线程中与其他PreparedStatements一起操作以更新其他行。这不一定必须工作(同样它取决于JDBC驱动程序,但与线程安全性没有直接关系)。我不确定最新版本,但较旧的Oracle JDBC驱动程序例如不支持多个语句,当然没有正确地失败,但是如你所描述的那样产生了意想不到的结果。如果我没记错的话,在迭代第一个语句的结果集时在连接上创建第二个语句会导致第一个语句被静默关闭,而第一个结果集只返回已经从数据库中提取的行,尽管行数更多本来可以的。您的实现听起来很相似,并且可能与其他数据库一样显示出类似的行为。
答案 2 :(得分:3)
PreparedStatement不要强制执行classe使这些方法线程安全。很明显,这取决于实施课程。
对于ex: - DelegatingPreparedStatement有这些方法,但那些不是线程安全的,而' OraclePreparedStatement '也有这些方法,那些是线程安全。
答案 3 :(得分:3)
正如jambjo指出的那样,规范要求线程安全。然而,正如Rakesh Juyal指出的那样,在实践中无法确保这种安全。因此,如果您想要真正可移植且强大,请尽可能避免对变量进行多线程访问,除非您确定所使用的驱动程序符合规范。
对于addBatch和executeBatch,这些方法在某些情况下本身是不可靠的。我知道每当我尝试将这些与Oracle驱动程序(单线程)一起使用时,我就会得到不可预知的结果。所以也许线程安全不是你的问题,而是批量。
答案 4 :(得分:1)
它可能非常适合JDBC的供应商。我宁愿永远不要依赖并发访问批处理并将并发的复杂性委托给数据库服务器。为什么不拥有更多独立的联系?