SqlHelper自定义的Sql工具类
1. 简单使用
boolean batchRes = SqlHelper.exeBatch(sqlSessionFactory, updateList, OrderItemMapper.class, (orderItemMapper, orderItem) -> {orderItemMapper.updateByExampleSelective(orderItem);
});
实现类需要先引入 SqlSessionFactory
,直接通过 @Autowired
即可,itemUpdateList
是传入的数据集合,OrderItemMapper
为指定的 Mapper 类型,后面的箭头函数会给一个指定 Mapper 的真实类,然后可以直接调用 Mapper 的方法。最后返回的 batchRes
为是否执行成功的结果,true 为成功,false 失败。
注意: 箭头函数中的 Mapper 使用的是 批处理SqlSession
,其用于自定义数据批量提交,与 Autowired
自动引入的 Mapper 不同,所以不允许在箭头函数中使用引入的 Mapper 来执行数据 更新
操作。
2. 自定义批次
boolean batchRes = SqlHelper.exeBatch(sqlSessionFactory, updateList, 2000, OrderItemMapper.class, (orderItemMapper, orderItem) -> {orderItemMapper.updateByExampleSelective(orderItem);
});
在数据集合参数后面传入 int 数值,可以自定义批次大小,按需要修改,默认是 1000,此值需要根据 数据库的连接超时时间
、数据包大小限制
、服务器性能
等诸多因素进行调整。
3. SqlSession 回调
boolean batchRes = SqlHelper.exeBatch(sqlSessionFactory, updateList, (sqlSession, orderItem) -> {OrderItemMapper mapper = sqlSession.getMapper(OrderItemMapper.class);mapper.updateByExampleSelective(orderItem);// 下面的一般不执行,这里仅做演示,exeBatch 会自动执行 commit 操作sqlSession.commit();
});
通过 SqlSession 回调,可以在箭头函数中获取到批处理 SqlSession,用于自定义一些 commit、rollback 等操作。同样也支持自定义批次大小。
4. 自定义循环
可以使用内置的循环方法
boolean batchRes = SqlHelper.exeBatch(sqlSessionFactory, sqlSession -> {SqlHelper.batchForeach(sqlSession, updateList, OrderItemMapper.class, (orderItemMapper, orderItem) -> {orderItemMapper.updateByExampleSelective(orderItem);});
});
或者自定义循环
boolean batchRes = SqlHelper.exeBatch(sqlSessionFactory, sqlSession -> {int batchSize = 1000;int size = updateList.size();int batchLimit = Math.min(batchSize, size);int i = 1;for (Iterator<OrderItem> iterator = updateList.iterator(); iterator.hasNext(); ++i) {OrderItem next = iterator.next();OrderItemMapper sqlSessionMapper = sqlSession.getMapper(OrderItemMapper.class);sqlSessionMapper.updateByExampleSelective(next);if (i == batchLimit) {// 超过批次大小提交一次sqlSession.flushStatements();// 计算新的最大值batchLimit = Math.min(batchLimit + batchSize, size);}}
});
4. 源码
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;import java.util.Collection;
import java.util.Iterator;
import java.util.function.BiConsumer;
import java.util.function.Consumer;/*** Sql工具类* <p>* 见 README_SQL_HELPER.md 文档说明** @author Jalon* @since 2025/9/22 11:54**/
public class SqlHelper {/*** 默认批次大小*/public static final Integer DEFAULT_BATCH_SIZE = 1000;/*** 执行批量操作** @param sqlSessionFactory SqlSessionFactory* @param list 数据集合* @param operation 批量操作* @param <T> 数据集合类* @return 是否执行成功*/public static <T> boolean exeBatch(SqlSessionFactory sqlSessionFactory, Collection<T> list, BiConsumer<SqlSession, T> operation) {return SqlHelper.exeBatch(sqlSessionFactory, list, DEFAULT_BATCH_SIZE, operation);}/*** 执行批量操作** @param sqlSessionFactory SqlSessionFactory* @param list 数据集合* @param mapperClass Mapper类* @param operation 批量操作* @param <T> 数据集合类* @param <M> Mapper类* @return 是否执行成功*/public static <T, M> boolean exeBatch(SqlSessionFactory sqlSessionFactory, Collection<T> list, Class<M> mapperClass, BiConsumer<M, T> operation) {return SqlHelper.exeBatch(sqlSessionFactory, list, DEFAULT_BATCH_SIZE, mapperClass, operation);}/*** 执行批量操作** @param sqlSessionFactory SqlSessionFactory* @param list 数据集合* @param batchSize 批次大小* @param operation 批量操作* @param <T> 数据集合类* @return 是否执行成功*/public static <T> boolean exeBatch(SqlSessionFactory sqlSessionFactory, Collection<T> list, int batchSize, BiConsumer<SqlSession, T> operation) {return SqlHelper.exeBatch(sqlSessionFactory, list, batchSize, SqlSession.class, operation);}/*** 执行批量操作** @param sqlSessionFactory SqlSessionFactory* @param list 数据集合* @param batchSize 批次大小* @param mapperClass Mapper类* @param operation 批量操作* @param <T> 数据集合类* @param <M> Mapper类* @return 是否执行成功*/public static <T, M> boolean exeBatch(SqlSessionFactory sqlSessionFactory, Collection<T> list, int batchSize, Class<M> mapperClass, BiConsumer<M, T> operation) {if (list == null || list.isEmpty()) {return false;}return SqlHelper.exeBatch(sqlSessionFactory, sqlSession -> {SqlHelper.batchForeach(sqlSession, list, batchSize, mapperClass, operation);});}/*** 执行批量操作** @param sqlSessionFactory SqlSessionFactory* @param operation 批量操作* @return 是否执行成功*/public static boolean exeBatch(SqlSessionFactory sqlSessionFactory, Consumer<SqlSession> operation) {// 参考MybatisPlusSqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();if (sqlSessionHolder != null) {SqlSession sqlSession = sqlSessionHolder.getSqlSession();//原生无法支持执行器切换,当存在批量操作时,会嵌套两个session的,优先commit上一个session//按道理来说,这里的值应该一直为false。sqlSession.commit(!transaction);}// end 参考MybatisPlusSqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);if (!transaction) {
// log.warn("SqlSession [" + sqlSession + "] Transaction not enabled");}try {operation.accept(sqlSession);// 非事务情况下,强制commit。sqlSession.commit(!transaction);return true;} catch (Throwable t) {sqlSession.rollback();throw t;} finally {sqlSession.close();}}/*** 批量循环操作** @param sqlSession SqlSession* @param list 数据集合* @param operation 批量操作* @param <T> 数据集合类型*/public static <T> void batchForeach(SqlSession sqlSession, Collection<T> list, BiConsumer<SqlSession, T> operation) {SqlHelper.batchForeach(sqlSession, list, SqlSession.class, operation);}/*** 批量循环操作** @param sqlSession SqlSession* @param list 数据集合* @param batchSize 批次大小* @param operation 批量操作* @param <T> 数据集合类型*/public static <T> void batchForeach(SqlSession sqlSession, Collection<T> list, int batchSize, BiConsumer<SqlSession, T> operation) {SqlHelper.batchForeach(sqlSession, list, batchSize, SqlSession.class, operation);}/*** 批量循环操作** @param sqlSession SqlSession* @param list 数据集合* @param mapperClass Mapper类* @param operation 批量操作* @param <T> 数据集合类型*/public static <T, M> void batchForeach(SqlSession sqlSession, Collection<T> list, Class<M> mapperClass, BiConsumer<M, T> operation) {SqlHelper.batchForeach(sqlSession, list, DEFAULT_BATCH_SIZE, mapperClass, operation);}/*** 批量循环操作** @param sqlSession SqlSession* @param list 数据集合* @param batchSize 批次大小* @param mapperClass Mapper类* @param operation 批量操作* @param <T> 数据集合类* @param <M> Mapper类*/public static <T, M> void batchForeach(SqlSession sqlSession, Collection<T> list, int batchSize, Class<M> mapperClass, BiConsumer<M, T> operation) {if (batchSize < 1) {throw new IllegalArgumentException("batchSize must be greater than 0");}int size = list.size();int batchLimit = Math.min(batchSize, size);M mapper = null;if (SqlSession.class.equals(mapperClass)) {mapper = (M) sqlSession;} else {mapper = sqlSession.getMapper(mapperClass);}if (mapper == null) return;int i = 1;for (Iterator<T> iterator = list.iterator(); iterator.hasNext(); ++i) {T next = iterator.next();// 执行批量操作operation.accept(mapper, next);if (i == batchLimit) {// 超过批次大小提交一次sqlSession.flushStatements();// 计算新的最大值batchLimit = Math.min(batchLimit + batchSize, size);}}}
}