基于Mybatis和BaseService的批量操作(MySql)

2024-04-20 18:58

本文主要是介绍基于Mybatis和BaseService的批量操作(MySql),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.通用Mapper

import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;/*** 基础mapper,实现增删改查,分页等基本功能** @param <T> 泛型参数* @author lw* @since 2019年2月14日 13:48:17*/
public interface BaseMapper<T> extends Mapper<T>, MySqlMapper<T> {
}

2.DO对象的Mapper继承通用Mapper

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.util.List;/*** @author lw* @since 2019年2月14日 13:50:22*/
@Mapper
public interface AdminMapper extends BaseMapper<Admin> {@Select("select * from t_wj_seats_admin")List<Admin> list();void batchInsert(List<Admin> admins);
}

3.通用BaseService,这里只定义了批量插入

import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;/*** 通用业务逻辑层** @author lw* @version 1.0* @since 2019/2/21 上午 11:26*/
public class BaseService<T> {@Autowiredprivate BaseMapper<T> baseMapper;@Autowiredprivate SqlSessionFactory sqlSessionFactory;protected final Class<T> doClass;private Integer batchCommitCount = 10000;public BaseService() {doClass = getGenericParamClass();}public BaseService(Integer batchCommitCount) {this.batchCommitCount = batchCommitCount;doClass = getGenericParamClass();}@Transactional(rollbackFor = Exception.class)public boolean batchInsert(List<T> DOs) {if (CollectionUtils.isEmpty(DOs)) {return false;}SqlSession sqlSession = null;// 新获取一个模式为BATCH,关闭自动提交的sessiontry {sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);// 通过新的sqlSession获取MapperBaseMapper mapper = (BaseMapper) sqlSession.getMapper(getMapperClass());for (int i = 0, len = DOs.size(); i < len; i++) {mapper.insertSelective(DOs.get(i));if (i % batchCommitCount == 0 && i >= batchCommitCount) {// 提交,无法回滚sqlSession.commit();sqlSession.clearCache();}}sqlSession.commit();sqlSession.clearCache();} catch (Exception e) {// 回滚sqlSession.rollback();e.printStackTrace();return false;} finally {sqlSession.close();}return true;}/*** 获取对应的Mapper Class** @return class*/private Class getMapperClass() {Class<?> clazz = baseMapper.getClass().getSuperclass();try {Field h = clazz.getDeclaredField("h");h.setAccessible(true);Object hObject = h.get(baseMapper);Field mapperInterface = hObject.getClass().getDeclaredField("mapperInterface");mapperInterface.setAccessible(true);Object mapperObject = mapperInterface.get(hObject);Field name = mapperObject.getClass().getDeclaredField("name");name.setAccessible(true);Object nameValue = name.get(mapperObject);return Class.forName((String) nameValue);} catch (Exception e) {e.printStackTrace();}throw new RuntimeException("基础BaseService中无法获取mapper真实Class对象");}/*** 获取泛型参数Class对象** @return Class对象*/private Class<T> getGenericParamClass() {ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();return (Class<T>) actualTypeArguments[0];}
}

4.连接url加入rewriteBatchedStatements=true

jdbc:mysql://localhost:3306/db?useSSL=false&rewriteBatchedStatements=true

4.具体业务逻辑类继承通用Service,直接调用父类的批量方法就好


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/*** 管理员业务逻辑类** @author lw* @since 2019年2月14日 15:43:08*/
@Service
public class AdminService extends BaseService<Admin> {@Autowiredprivate AdminMapper mapper;@Transactional(rollbackFor = Exception.class)public void test() {List<Admin> admins = genList();long startTime = System.currentTimeMillis();batchInsert(admins);long endTime = System.currentTimeMillis();System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) +"  baseService 批量插入" + admins.size() + "条 耗时(ms):" + (endTime - startTime));}private List<Admin> genList() {int len = 100;List<Admin> admins = new ArrayList<>(len);for (int i = 0; i < len; i++) {Admin admin = new Admin();admin.setUsername("测试" + i);admins.add(admin);}return admins;}
}

以上批量操作就完成啦

-------------------------------------------------------------------------------------------------------------------------------------------------

将BaseService的批量插入与使用xml的foreach进行批量插入进行性能对比

1.xml文件

<insert id="batchInsert" parameterType="java.util.List">insert t_admin (username)values<foreach collection="list" item="admin" separator=",">(#{admin.username})</foreach>
</insert>

2.测试类

 @Transactional(rollbackFor = Exception.class)public void test() {List<Admin> admins = genList();long startTime = System.currentTimeMillis();batchInsert(admins);long endTime = System.currentTimeMillis();System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) +"  baseService 批量插入" + admins.size() + "条 耗时(ms):" + (endTime - startTime));}@Transactional(rollbackFor = Exception.class)public void test1() {List<Admin> admins = genList();long startTime = System.currentTimeMillis();mapper.batchInsert(admins);long endTime = System.currentTimeMillis();System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) +"  xml foreach 批量插入" + admins.size() + "条 耗时(ms):" + (endTime - startTime));}private List<Admin> genList() {int len = 100;List<Admin> admins = new ArrayList<>(len);for (int i = 0; i < len; i++) {Admin admin = new Admin();admin.setUsername("测试" + i);admins.add(admin);}return admins;}

3.结果分析

性能对比表格
 5千条数据一万五千条数据十万条数据一千万条数据
xml的foreach的批量插入 耗时(ms)1533882901OutOfMemoryError
BaseService的批量插入 耗时(ms)391139929035时间太长,未计量,但确实可以插入

可以看到,使用xml的foreach的批量插入方式相对而言效率要高很多,当数据量很大时,会耗空内存,

但是这可以进行编程控制,比如进行多次的批量插入.

这篇关于基于Mybatis和BaseService的批量操作(MySql)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/921058

相关文章

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

Python中文件读取操作漏洞深度解析与防护指南

《Python中文件读取操作漏洞深度解析与防护指南》在Web应用开发中,文件操作是最基础也最危险的功能之一,这篇文章将全面剖析Python环境中常见的文件读取漏洞类型,成因及防护方案,感兴趣的小伙伴可... 目录引言一、静态资源处理中的路径穿越漏洞1.1 典型漏洞场景1.2 os.path.join()的陷

如何解决Druid线程池Cause:java.sql.SQLRecoverableException:IO错误:Socket read timed out的问题

《如何解决Druid线程池Cause:java.sql.SQLRecoverableException:IO错误:Socketreadtimedout的问题》:本文主要介绍解决Druid线程... 目录异常信息触发场景找到版本发布更新的说明从版本更新信息可以看到该默认逻辑已经去除总结异常信息触发场景复

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

MySQL 表的内外连接案例详解

《MySQL表的内外连接案例详解》本文给大家介绍MySQL表的内外连接,结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录表的内外连接(重点)内连接外连接表的内外连接(重点)内连接内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示

Python中OpenCV与Matplotlib的图像操作入门指南

《Python中OpenCV与Matplotlib的图像操作入门指南》:本文主要介绍Python中OpenCV与Matplotlib的图像操作指南,本文通过实例代码给大家介绍的非常详细,对大家的学... 目录一、环境准备二、图像的基本操作1. 图像读取、显示与保存 使用OpenCV操作2. 像素级操作3.

MySQL的ALTER TABLE命令的使用解读

《MySQL的ALTERTABLE命令的使用解读》:本文主要介绍MySQL的ALTERTABLE命令的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、查看所建表的编China编程码格式2、修改表的编码格式3、修改列队数据类型4、添加列5、修改列的位置5.1、把列

Java如何从Redis中批量读取数据

《Java如何从Redis中批量读取数据》:本文主要介绍Java如何从Redis中批量读取数据的情况,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一.背景概述二.分析与实现三.发现问题与屡次改进3.1.QPS过高而且波动很大3.2.程序中断,抛异常3.3.内存消

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL