iBatis batch处理那些事详解编程语言
编程语言 详解 处理 那些 Batch ibatis
2023-06-13 09:20:40 时间
Java代码
public Object batchExecute(final CallBack callBack) {
Object result = getSqlMapClientTemplate().execute(new SqlMapClientCallback Object () {
@Override
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
executor.startBatch();
Object obj = callBack.execute(new IbatisSqlExecutor(executor));
executor.executeBatch();
return obj;
}
});
return result;
}
Java代码
public interface SqlExecutor {
Object insert(String id, Object parameterObject) throws SQLException;
Object insert(String id) throws SQLException;
int update(String id, Object parameterObject) throws SQLException;
int update(String id) throws SQLException;
int delete(String id, Object parameterObject) throws SQLException;
int delete(String id) throws SQLException;
Object queryForObject(String id, Object parameterObject) throws SQLException;
Object queryForObject(String id) throws SQLException;
Object queryForObject(String id, Object parameterObject, Object resultObject) throws SQLException;
}
Java代码
class IbatisSqlExecutor implements SqlExecutor {
private SqlMapExecutor executor;
IbatisSqlExecutor(SqlMapExecutor executor) {
this.executor = executor;
}
@Override
public Object insert(String id, Object parameterObject) throws SQLException {
return executor.insert(id, parameterObject);
}
// 剩下的就省略了,和insert都类似
}
Java代码
public interface CallBack {
Object execute(SqlExecutor executor);
}
Java代码
getDao().batchExecute(new CallBack() {
@Override
public Object execute(SqlExecutor executor) {
for (int i = 0; i 10000; ++i) {
// 注意每个sql_id的sql语句都是不相同的
executor.insert( id1 , obj1);
executor.insert( id2 , obj2);
//
executor.insert( idn , objn);
}
return null;
}
});
Java代码
// 以下代码来自com.ibatis.sqlmap.engine.execution.SqlExecutor$Batch
public void addBatch(StatementScope statementScope, Connection conn, String sql, Object[] parameters) throws SQLException {
PreparedStatement ps = null;
// 就是它:currentSql
if (currentSql != null currentSql.equals(sql)) {
int last = statementList.size() 1;
ps = (PreparedStatement) statementList.get(last);
} else {
ps = prepareStatement(statementScope.getSession(), conn, sql);
setStatementTimeout(statementScope.getStatement(), ps);
// 就是它:currentSql
currentSql = sql;
statementList.add(ps);
batchResultList.add(new BatchResult(statementScope.getStatement().getId(), sql));
}
statementScope.getParameterMap().setParameters(statementScope, ps, parameters);
ps.addBatch();
size++;
}
Java代码
getDao().batchExecute(new CallBack() {
@Override
public Object execute(SqlExecutor executor) {
for (int i = 0; i 10000; ++i) {
executor.insert( id1 , obj1);
}
for (int i = 0; i 10000; ++i) {
executor.insert( id2 , obj2);
}
// 你就反复写for循环吧
return null;
}
});
Java代码
public void addBatch(StatementScope statementScope, Connection conn, String sql, Object[] parameters) throws SQLException {
PreparedStatement ps = statementMap.get(sql);
if (ps == null) {
ps = prepareStatement(statementScope.getSession(), conn, sql);
setStatementTimeout(statementScope.getStatement(), ps);
statementMap.put(sql, ps);
batchResultMap.put(sql, new BatchResult(statementScope.getStatement().getId(), sql));
}
statementScope.getParameterMap().setParameters(statementScope, ps, parameters);
ps.addBatch();
++size;
}
Java代码
private static class Batch {
private Map String, PreparedStatement statementMap = new HashMap String, PreparedStatement
private Map String, BatchResult batchResultMap = new HashMap String, BatchResult
private int size;
/**
* Create a new batch
*/
public Batch() {
size = 0;
}
/**
* Getter for the batch size
* @return the batch size
*/
@SuppressWarnings( unused )
public int getSize() {
return size;
}
/**
* Add a prepared statement to the batch
* @param statementScope the request scope
* @param conn the database connection
* @param sql the SQL to add
* @param parameters the parameters for the SQL
* @throws SQLException if the prepare for the SQL fails
*/
public void addBatch(StatementScope statementScope, Connection conn, String sql, Object[] parameters) throws SQLException {
PreparedStatement ps = statementMap.get(sql);
if (ps == null) {
ps = prepareStatement(statementScope.getSession(), conn, sql);
setStatementTimeout(statementScope.getStatement(), ps);
statementMap.put(sql, ps);
batchResultMap.put(sql, new BatchResult(statementScope.getStatement().getId(), sql));
}
statementScope.getParameterMap().setParameters(statementScope, ps, parameters);
ps.addBatch();
++size;
}
/**
* TODO (Jeff Butler) maybe this method should be deprecated in some release,
* and then removed in some even later release. executeBatchDetailed gives
* much more complete information.
* p/
* Execute the current session s batch
* @return the number of rows updated
* @throws SQLException if the batch fails
*/
public int executeBatch() throws SQLException {
int totalRowCount = 0;
for (Map.Entry String, PreparedStatement iter : statementMap.entrySet()) {
PreparedStatement ps = iter.getValue();
int[] rowCounts = ps.executeBatch();
for (int j = 0; j rowCounts.length; j++) {
if (rowCounts[j] == Statement.SUCCESS_NO_INFO) {
// do nothing
} else if (rowCounts[j] == Statement.EXECUTE_FAILED) {
throw new SQLException( The batched statement at index + j + failed to execute. );
} else {
totalRowCount += rowCounts[j];
}
}
}
return totalRowCount;
}
/**
* Batch execution method that returns all the information
* the driver has to offer.
* @return a List of BatchResult objects
* @throws BatchException (an SQLException sub class) if any nested
* batch fails
* @throws SQLException if a database access error occurs, or the drive
* does not support batch statements
* @throws BatchException if the driver throws BatchUpdateException
*/
@SuppressWarnings({ rawtypes , unchecked })
public List executeBatchDetailed() throws SQLException, BatchException {
List answer = new ArrayList();
int i = 0;
for (String sql : statementMap.keySet()) {
BatchResult br = batchResultMap.get(sql);
PreparedStatement ps = statementMap.get(sql);
try {
br.setUpdateCounts(ps.executeBatch());
} catch (BatchUpdateException e) {
StringBuffer message = new StringBuffer();
message.append( Sub batch number );
message.append(i + 1);
message.append( failed. );
if (i 0) {
message.append( );
message.append(i);
message.append( prior sub batch(s) completed successfully, but will be rolled back. );
}
throw new BatchException(message.toString(), e, answer, br.getStatementId(), br.getSql());
}
++i;
answer.add(br);
}
return answer;
}
/**
* Close all the statements in the batch and clear all the statements
* @param sessionScope
*/
public void cleanupBatch(SessionScope sessionScope) {
for (Map.Entry String, PreparedStatement iter : statementMap.entrySet()) {
PreparedStatement ps = iter.getValue();
closeStatement(sessionScope, ps);
}
statementMap.clear();
batchResultMap.clear();
size = 0;
}
}
![收藏代码](http://blog.ytso.com/zb_users/plugin/LazyLoad/usr/loading.gif)
不想将SqlMapExecutor侵入到业务代码中,于是又有了如下3个类,在今天的主题中不是关键,可以忽略,只是为了将代码贴完整
Java代码
![收藏代码](http://blog.ytso.com/zb_users/plugin/LazyLoad/usr/loading.gif)
Java代码
![收藏代码](http://blog.ytso.com/zb_users/plugin/LazyLoad/usr/loading.gif)
Java代码
![收藏代码](http://blog.ytso.com/zb_users/plugin/LazyLoad/usr/loading.gif)
Java代码
![收藏代码](http://blog.ytso.com/zb_users/plugin/LazyLoad/usr/loading.gif)
再然后 尼玛不但速度没变快还异常了,原因竟然是生成了太多的PreparedStatement,你妹不是批处理吗?不是应该一个sql只有一个PreparedStatement吗?
跟踪iBatis代码,发现了iBatis是这样处理的
Java代码
![收藏代码](http://blog.ytso.com/zb_users/plugin/LazyLoad/usr/loading.gif)
不细解释了,只看currentSql这个实例变量就知道了,如果sql与前一次不同那么会新建一个PreparedStatement,所以刚才的伪代码应该这样写:
Java代码
![收藏代码](http://blog.ytso.com/zb_users/plugin/LazyLoad/usr/loading.gif)
很不爽是不?反正我是决了一个定,改iBatis的源码
改源码最好这么来:
1.复制对应类的源码到工程下,本例中要复制的是com.ibatis.sqlmap.engine.execution.SqlExecutor
注意要保持包名,其实是类的全限定名称要一样哇,这样根据ClassLoader的类加载机制会先加载你工程中的SqlExecutor而不加载iBatis jar包中的对应SqlExecutor
如图:
2.改之,只改static class Batch这个内部类即可,策略是去掉currentSql,将PreparedStatement放入HashMap
如下:
Java代码
![收藏代码](http://blog.ytso.com/zb_users/plugin/LazyLoad/usr/loading.gif)
下面贴出修改后完整的代码,方便有同样需求的同学修改,只贴出内部类com.ibatis.sqlmap.engine.execution.SqlExecutor$Batch,com.ibatis.sqlmap.engine.execution.SqlExecutor没有做出任何修改
Java代码
![收藏代码](http://blog.ytso.com/zb_users/plugin/LazyLoad/usr/loading.gif)
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/13584.html
cjava相关文章
- Python算法:如何解决楼梯台阶问题详解编程语言
- Python 处理各种编码的字符串详解编程语言
- Python ftp client 处理含有中文的文件名详解编程语言
- Python的时间转换详解编程语言
- jquery实现的时间轴详解编程语言
- Java处理XSS漏洞的工具类代码详解编程语言
- Java DES 加密/解密详解编程语言
- JDBC: 批量处理提高SQL处理速度详解编程语言
- 获得Java类属于哪个包的代码详解编程语言
- Java异常处理之InvocationTargetException(反射异常)详解编程语言
- python_Day42_锁和队列详解编程语言
- ibatis 对事务和批量提交的处理,以及回滚的处理详解编程语言
- J2EE系统异常的处理准则详解编程语言
- 页面传入json数组参数的处理代码详解编程语言
- 一个完整的Lucene搜索引擎例子demo详解编程语言
- 详解equals()方法和hashCode()方法编程语言
- jsp页面如何对时间进行格式化处理详解编程语言
- Java导出Excel表(poi)名中文乱码问题处理详解编程语言
- Spring Boot2.0之 整合Zookeeper集群详解编程语言
- jdbc.properties文件的配置信息详解编程语言
- java的多线程安全,ReentrantLock与synchronized锁详解编程语言
- sap表维护工具来维护自定义表详解编程语言
- Boost多线程编程详解编程语言
- BDC中日期和数量格式的转换处理详解编程语言
- ALV调用的几个标准函数详解编程语言
- BDC应用详解编程语言
- ABAP 7.4新特性(四): COND SWITCH 操作符详解编程语言