是否有可能以某种方式将PreparedStatement批处理与Statement批处理混合使用,并保留在单个事务中执行的两者的好处?
我拥有的是我自己的数据访问对象,它代表了事务。我想这样使用它:
/* here transaction starts: object receive connection, etc. */
MyTableTransactionObject myTable = new MyTableTransactionObject();
myTable.clear();
myTable.insert(Row1);
myTable.insert(Row2);
myTable.insert(Row3);
myTable.doSomethingElse();
myTable.insert(Row4);
/* here transaction ends, batches are executed changes are commited,
statements are closed */
myTable.execute();
myTable.close();
MyTableTransactionObject的“引擎盖”下有使用Statement或PreparedStatements的方法(可能有多个PreparedStatements)。例如:在clear()
方法中,我想使用statement.addBatch("DELETE FROM table;")
,在insert(...)
方法中我想使用特殊的PreparedStatement来执行SQL INSERT
操作,在doSomethingElse(...)
我想要将不同的PreparedStatement用于其他事情等等。
如何在myTable.execute()
答案 0 :(得分:1)
这不是最优雅的解决方案,您将从性能中支付%$#,但它确实有效。
public class DBEngine {
private final int defaultBatchSize = 1000;
private Pool pool = null;
private Connection con = null;
private PreparedStatement ps = null;
private ArrayList<PreparedStatement> globalBatch = new ArrayList<PreparedStatement>();
private int k = 0; //bean-wide batch counter
private boolean debugMode = false;
private PreparedStatement batchPs = null;
//--------------------------------
DBEngine(){
this.pool = new Pool();
this.con = pool.getConnection();
this.ps = null;
this.k = 0; //bean-wide batch counter
}
//-------------
boolean mixedBatchTime(boolean force){
return mixedBatchTime(defaultBatchSize, force);
}
//-------------
boolean mixedBatchTime(int customBatchSize){
return mixedBatchTime(customBatchSize, false);
}
//-------------
boolean mixedBatchTime(){
return mixedBatchTime(defaultBatchSize, false);
}
//-------------
// Executes a mixed batch of PreparedStatements
//-------------
boolean mixedBatchTime(int customBatchSize, boolean force){
if(k > customBatchSize - 1 || force){
try {
StringBuilder sqlStmt = new StringBuilder();
for(int i = 0; i < globalBatch.size(); i++){
sqlStmt.append(globalBatch.get(i) + "; ");
}
batchPs = con.prepareStatement(sqlStmt.toString());
batchPs.execute();
ps = null;
sqlStmt = null;
batchPs = null;
} catch (SQLException e) {
e.printStackTrace();
}
k = 0;
globalBatch = null;
globalBatch = new ArrayList<PreparedStatement>();
return true;
}else return false;
}
}
您必须在实际的批处理准备部分中增加k,该部分
//------------------------------------------
boolean updateSomeQuantity(int someID, int someQuantity){
try{
// detects if the statement has changed in order to recompile it only once per change
if(ps!=null && !ps.toString().contains("UPDATE sometable SET somequantity =")){
ps = null;
String updateStmt = "UPDATE sometable SET somequantity = ? WHERE someID = ?";
ps = con.prepareStatement(updateStmt);
}else if(ps == null){
String updateStmt = "UPDATE sometable SET somequantity = ? WHERE someID = ?";
ps = con.prepareStatement(updateStmt);
}
ps.setInt(1, someQuantity)
ps.setInt(2, someID);
globalBatch.add(ps);
k++; // very important
return true;
} catch (SQLException e) {
e.printStackTrace();
if(e.getNextException() != null) e.getNextException().printStackTrace();
return false;
}
}
实际的实现是在另一个代码中,在该代码中,您实例化DBEngine bean的一个实例,并在循环中使用updateSomeQuantity(somequantity)方法和mixedBatchTime()方法。循环结束后,调用mixedBatchTime(true)来批处理剩余的任何内容。
注意:此解决方案使用AutoCommit(true)
答案 1 :(得分:0)
如果您的Statements / PreparedStatements共享一个公共连接,并且您没有在该Connection上提交该事务,那么他们将共享一个共同的事务。