重复使用PreparedStatement多次
在使用PreparedStatement和一个没有任何池的公共连接的情况下,我是否可以重新创build一个实例,以保证每个准备好语句的dml / sql操作?
我的意思是:
for (int i=0; i<1000; i++) { PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setObject(1, someValue); preparedStatement.executeQuery(); preparedStatement.close(); }
代替:
PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i=0; i<1000; i++) { preparedStatement.clearParameters(); preparedStatement.setObject(1, someValue); preparedStatement.executeQuery(); } preparedStatement.close();
我的问题是由于我想把这个代码放到multithreading的环境中,你能给我一些build议吗? 谢谢
第二种方法是效率更高一点,但更好的方法是分批执行它们:
public void executeBatch(List<Entity> entities) throws SQLException { try ( Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL); ) { for (Entity entity : entities) { statement.setObject(1, entity.getSomeProperty()); // ... statement.addBatch(); } statement.executeBatch(); } }
但是,您依赖于JDBC驱动程序实现一次可以执行多less个批处理。 例如,你可能想要每1000个批次执行一次:
public void executeBatch(List<Entity> entities) throws SQLException { try ( Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL); ) { int i = 0; for (Entity entity : entities) { statement.setObject(1, entity.getSomeProperty()); // ... statement.addBatch(); i++; if (i % 1000 == 0 || i == entities.size()) { statement.executeBatch(); // Execute every 1000 items. } } } }
对于multithreading环境,如果您使用try-with-resources语句根据正常的JDBC语法在相同的方法块内获取并closures连接和语句,则不必担心这一点。以上片段。
如果这些批处理是事务性的,那么您想closures连接的自动提交,并且只有在所有批处理完成后才提交事务。 否则,当第一批批次成功时,可能会导致数据库脏。
public void executeBatch(List<Entity> entities) throws SQLException { try (Connection connection = dataSource.getConnection()) { connection.setAutoCommit(false); try (PreparedStatement statement = connection.prepareStatement(SQL)) { // ... try { connection.commit(); } catch (SQLException e) { connection.rollback(); throw e; } } } }
代码中的循环只是一个过分简化的例子,对吧?
最好只创build一次PreparedStatement,并在循环中重复使用它。
在不可能的情况下(因为它太复杂的程序stream),使用PreparedStatement仍然是有益的,即使你只使用一次,因为工作的服务器端(parsingSQL和caching执行计划),仍然会减less。
为了解决您希望重新使用Java端PreparedStatement的情况,一些JDBC驱动程序(如Oracle)具有cachingfunction:如果在同一个连接上为同一个SQL创build一个PreparedStatement,它将会给您相同的(caching)实例。
关于multithreading:我不认为JDBC连接可以跨多个线程共享(即multithreading同时使用)。每个线程都应该从池中获取自己的连接,使用它,然后再次将其返回给池。