前言
mybatis架构下使用BatchExecutor获取JDBC对批处理的支持,实现数据的批量删除
一、boot项目批量处理(牺牲事务和代码量换取效率)
public Json deleteBatchByIds(List<String> ids) {
SqlSession session =sqlSessionFactory.openSession(ExecutorType.BATCH);
DcDispatchDeptRelateManageMapper mapper = session.getMapper(DcDispatchDeptRelateManageMapper.class);
for (String id: ids) {
mapper.deleteByPrimaryKey(id);
}
session.commit();
session.close();
return new Json(){{
put("code","200");
put("msg","批量删除成功!");
}};
}
boot项目sqlSessionFactory通过springBean管理,直接注入即可
创建了一个使用BatchExecutor的SqlSession,也可以是SqlSessionTemplate,其实现了SqlSession接口,底层通过一个SqlSession代理进行相应的操作。然后在循环中一次调用对应Mapper的删除操作,相当于调用BatchExecutor的doUpdate(),最后调用SqlSession的commit()方法提交事务,在SqlSession的commit()中会调用Executor的commit(),从而导致了executeBatch()的发生。
无法获取受影响行数,也无法使用事务捕获异常和回滚
问题详情见https://bbs.csdn.net/topics/391003902
二、底层方法(支持编程式事务)
dataSource直接注入
public Json deleteBatchByIds(List<String> ids) {
Json result =new Json();
result.put("code", "500");
Connection conn = DataSourceUtils.getConnection(dataSource);
long setData=0;
long setDataEnd=0;
long startExecute=0;
long endExecute=0;
long startRollBack=0;
long endRollBack=0;
try {
setData=System.currentTimeMillis();
conn.setAutoCommit(false);
PreparedStatement pst = conn.prepareStatement("delete from DC_DISPATCH_DEPT_RELATE_MANAGE where ID=?");
for (int i = 0; i < ids.size(); i++) {
pst.setString(1, ids.get(i));
pst.addBatch();
}
setDataEnd=System.currentTimeMillis();
startExecute=System.currentTimeMillis();
pst.executeBatch();
endExecute=System.currentTimeMillis();
int updateCount = pst.getUpdateCount();
if (updateCount<ids.size()){
startRollBack=System.currentTimeMillis();
conn.rollback();
endRollBack=System.currentTimeMillis();
result.put("msg", "存在未知数据,批量删除失败!");
return result;
}
conn.commit();
result.put("code", "200");
result.put("msg", "批量删除成功");
return result;
} catch (SQLException e) {
log.error("SQLException:"+e.getMessage());
try {
startRollBack=System.currentTimeMillis();
conn.rollback();
endRollBack=System.currentTimeMillis();
} catch (SQLException sqlException) {
log.error("数据回滚异常!");
log.error("------------DataSource connection rollBack exception !-------------"+sqlException.getMessage());
}
result.put("msg", "SQLException,删除失败!"+e.getMessage());
return result;
}finally {
log.warn("数据装填:[{}],添加到批次:[{}],回滚:[{}]",setDataEnd-setData,endExecute-startExecute,endRollBack-startRollBack);
try {
conn.close();
} catch (SQLException sqlException) {
log.error("------------DataSource connection close exception !-------------"+sqlException.getMessage());
}
}
}
总结
在数据量为十万的时候,采用batchExecutor是simpleExecutor效率的100倍左右,避免用 IN 关键字导致锁表时间过长影响系统其他功能,数据量少的时候推荐使用第一种方式。
借鉴内容:
Mybatis中的批处理
MybatisPlus批处理源码分析