我使用JDBC,autocommit = true。在其中一个操作中,我使用预处理语句进行批量插入。
public void executeBatchInsert(String query, List<Object[]> entityList) {
try {
pstmt = conn.prepareStatement(query);
for(int i=0; i<entityList.size(); i++) {
int j=1;
for(Object o: entityList.get(i)) {
pstmt.setObject(j++, formatColumnValue(o));
}
pstmt.addBatch();
if((i+1)%1000 == 0) {
pstmt.executeBatch();
}
}
pstmt.executeBatch();
} catch (SQLException e) {
}
}
如果我在执行它时遇到异常,当我关闭此连接时,是否会释放所有锁并发生回滚?
- B. Teja。
答案 0 :(得分:4)
你问题的直接答案是:不。如果发生异常,您必须手动调用rollback
方法。在此之前,您必须setAutoCommit
到false
。默认情况下,自动提交设置为true
。如果自动提交设置为true
,则无法执行rollback
,系统会exception
告诉您。
稍后请不要忘记将autoCommit
设置回true
,否则您可能会遇到其他方法的不可预期的结果。
以下是有关如何实现此功能的示例。这只是草图,您应该更多地关注如何处理connection
,prepared statment
,exception
等等。
public void insertAndRollback(Connection connection) {
try {
final ArrayList parameters = new ArrayList();
// Add your parameters to the arraylist
parameters.add("John");
parameters.add("Lee");
parameters.add("Mary");
parameters.add("Peter");
parameters.add("Lewis");
parameters.add("Patrick");
final String parameterizedQuery = "insert into person (name) values (?)";
final int batchSize = 5; // Set your batch size here
int count = 0;
int aux = 0;
// Get the total number of '?' in the query
int totalQueryParameters = Utils.countCharOccurrences(parameterizedQuery, '?');
final int auxTotalQueryParameters = totalQueryParameters;
final PreparedStatement preparedStatement = connection.prepareStatement(parameterizedQuery);
// Auto Commit must be set to false
connection.setAutoCommit(false);
for(int i = 0; i < parameters.size(); i++)
{
Object obj = parameters.get(i);
aux++;
preparedStatement.setObject(aux, obj);
if(totalQueryParameters == i + 1) { // Because the ArrayList starts from zero.
// First query "parsed" - > Add to batch
preparedStatement.addBatch();
// One query has been added to the batch. Re-adapt the cycle.
totalQueryParameters = totalQueryParameters + auxTotalQueryParameters;
aux = 0;
}
if(++count % batchSize == 0) {
preparedStatement.executeBatch();
}
}
preparedStatement.executeBatch(); // insert remaining queries
preparedStatement.close();
connection.setAutoCommit(true); // Make it back to default.
} catch (SQLException ex) {
// Do the rollback
doRollback(connection);
try {
// Make it back to default.
connection.setAutoCommit(true);
} catch (SQLException ex1) {
ex1.printStackTrace();
}
// Dont forget to close the preparedStatement and the connection
// if you don't need the connection open any more.
ex.printStackTrace();
}
}
private void doRollback(Connection c) {
try {
c.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
答案 1 :(得分:2)
事实上,PreparedStatement.executeBatch没有澄清问题,可能在其他地方,但我确信它不是原子操作,因为SQL没有批处理操作,所以executeBatch在数据库级别分别执行每个语句。我在MySQL上测试过它:
t1是一个空表,其中n1 INT(11)为非空列,autocommit = true
ResultSet rs1 = conn.createStatement().executeQuery("select count(*) from t1");
rs1.next();
System.out.println(rs1.getInt(1));
String query = "insert into t1 (n1) values(?)";
PreparedStatement ps = conn.prepareStatement(query);
ps.setObject(1, 1);
ps.addBatch();
ps.setObject(1, null);
ps.addBatch();
try {
ps.executeBatch();
} catch (Exception e) {
System.out.println(e);
}
ResultSet rs2 = conn.createStatement().executeQuery("select count(*) from t1");
rs2.next();
System.out.println(rs2.getInt(1));
打印
0
java.sql.BatchUpdateException: Column 'n1' cannot be null
1
即批次中有2个插入;第一次成功,第二次失败,仍然t1获得1行
答案 2 :(得分:1)
autocommit=true
。
话虽如此,我建议使用getUpdateCount()
并构建逻辑来执行剩余。
最后commit