批量插入数据(基于Mybatis的实现-Oracle)

摘要:
Mybatis(全局/本地)批处理的性能类似于Java自己的批处理。首先,Mybatis全局设置批处理从Spring Mybatis.xml配置信息、Spring Mybatis.xml和MybatisConfig.xml开始(在本项目中,DB中的insert、update和delete方法无法返回DML影响DB_TABLE的行数。

前言:做一个数据同步项目,要求:同步数据不丢失的情况下,提高插入性能。

项目DB框架:Mybatis。DataBase:Oracle。

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

批量插入数据方式:

一、Mybatis 全局设置批处理;

二、Mybatis 局部设置批处理;

三、Mybatis foreach批量插入:

①SELECT UNION ALL;

②BEGIN INSERT INTO ...;INSERT INTO...;...;END;

四、java自带的批处理插入;

五、其他方式

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

先说结论:Mybatis(全局/局部)批处理和java自带的批处理 性能上差不多,属于最优处理办法,我这边各种测试后,最后采用Mybatis局部批处理方式。

一、Mybatis 全局设置批处理

先上Spring-Mybatis.xml 配置信息

批量插入数据(基于Mybatis的实现-Oracle)第1张 Spring-Mybatis.xml

再上mybatisConfig.xml(在本项目中,我没有设置setting。最终采用的局部批处理,因此未设置全局批处理,具体原因后面再说。)

批量插入数据(基于Mybatis的实现-Oracle)第2张 mybatisConfig.xml

这样子设置好后,在BaseService开放saveBatch(List<T> list)方法

批量插入数据(基于Mybatis的实现-Oracle)第3张 BaseService.saveBatch(List list)

虽然看上去是500条记录,一次次INSERT INTO,但由于在全局已经设置Mybatis是批处理执行器,所以这500条INSERT INTO只会与Oracle数据库通信一次。

全局设置批处理的局限性在哪里呢?

先附上mybatis官方的讨论列表中最很关键的一句:“If the BATCH executor is in use, the update counts are being lost. ”

设置全局批处理后,DB里的insert、Update和delete方法,都无法返回进行DML影响DB_TABLE的行数。

1.insert 无法返回影响的行数,这个好解决,一个批处理放在一个事务里,记录批处理失败次数,总数-批处理失败次数*单位批处理数据量,就能得到insert 影响DB_TABLE的行数;

2.但是update和delete就无法很简单的去统计影响行数了,如果做反复查询,反而降低了效率,得不偿失。

虽现在的项目尚未有需要反馈影响DB_TABLE行数的需求,但是为了更灵活,我们放弃了全局批处理的方式。

!这里提个疑问:为什么Mybatis官方,不将批处理的选择方式下沉到方法级别?方便开发者根据实际情况,灵活选择。我觉得这是个可以改进的地方,如有机会,可看源码去进行改进。

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

二、Mybatis局部批处理方式

由于领导说全局批处理方式,不够灵活,不适宜项目所需,要另想办法支持。但是java自带的批处理,因为项目代码管理的要求,也不能采用。因此,在仔细阅读官方文档后,设想自己能否获取SQLSession后openSession,将这个会话设置为批处理呢?

先看MyBatis官方网站(须FanQiang):http://www.mybatis.org/mybatis-3/zh/getting-started.html

批量插入数据(基于Mybatis的实现-Oracle)第4张 官方建议的写法

后查阅Mybatis java API(须FanQiang):  http://www.mybatis.org/mybatis-3/zh/java-api.html

现在你有一个 SqlSessionFactory,可以用来创建 SqlSession 实例。

SqlSessionFactory

SqlSessionFactory 有六个方法可以用来创建 SqlSession 实例。通常来说,如何决定是你 选择下面这些方法时:

  • Transaction (事务): 你想为 session 使用事务或者使用自动提交(通常意味着很多 数据库和/或 JDBC 驱动没有事务)?
  • Connection (连接): 你想 MyBatis 获得来自配置的数据源的连接还是提供你自己
  • Execution (执行): 你想 MyBatis 复用预处理语句和/或批量更新语句(包括插入和 删除)

重载的 openSession()方法签名设置允许你选择这些可选中的任何一个组合。

批量插入数据(基于Mybatis的实现-Oracle)第5张 官方提供的openSession方法

因此出来了局部批处理第一套代码实现方式:

批量插入数据(基于Mybatis的实现-Oracle)第6张 sqlSession(List data)
批量插入数据(基于Mybatis的实现-Oracle)第7张 mybatis-dataSource.xml

已经在Spring-Mybatis.xml 中配置了SQLSessionFactory,那我为何还要自己去创建SQLSessionFactory呢?因此继续改良代码

批量插入数据(基于Mybatis的实现-Oracle)第8张 mybatisSqlSession(List data)

这个版本的局部批处理插入是比较满意的,最终采用的方式也是这个版本。

下面放出在IService接口定义和Service的具体实现代码:

IService接口定义

批量插入数据(基于Mybatis的实现-Oracle)第9张 saveBatch(List data,Class mClass)

Service实现

批量插入数据(基于Mybatis的实现-Oracle)第10张 saveBatch(List data,Class mClass)

局部和全局批处理插入对比:局部批处理,可以对特定一类的方法,进行数据批处理,不会影响其他DML语句,其他DML语句,可以正常返回影响DB_TABLE的行数。

!这样既能针对特殊需求(批处理)支持,也能支持未来需要返回影响数据行的要求。

注意:使用批处理方式进行DML操作,是无法反馈影响DB_TABLE行数的数据。无论是局部批处理还是java自带的批处理方式,皆无法反馈DB_TABLE count。

补充完善:

在我的Service实现中,通过注入的方式,获取mapper的实例

批量插入数据(基于Mybatis的实现-Oracle)第11张 Service

前面的Service saveBatch方法中,还需要传入指定的Mapper.class.对本项目其他开发者来说,与之前的环境相比,多传一个参数感觉别扭。

那么为何我不继续封装,外部无需传入Mapper.class,而是通过内部注入的mapper实例获取Mapper.class.
改良后的代码:

批量插入数据(基于Mybatis的实现-Oracle)第12张 saveBatch(List data)

这里对mapper实例进行一个简短的说明:

1.mapper实例是通过java动态代理来实例化的;

2.mapper的SQLSession是使用mybatis统一的配置实例的;

3.mapper的默认执行器是SIMPLE(普通的执行器);

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

 三、Mybatis foreach批量插入

Mybatis foreach 批量插入,如果批量插入的数据量大,不得不说这真是一个非常糟糕的做法

无论是SELECT ** UNION ALL 还是BEGIN ...;END; ,相对而言后者比前者稍微好点。

放出DB和我测试的结果:

耗时占当时整个数据库CPU百分比说明
15.598.33union all方式拼接插入
16.497.75begin end方式插入块
1.5464.81java 自带的batch方式插入

①foreach union all的批量插入,现已有大量的博客资源可供参考,我就不贴出自己的实现方式了。

如果有兴趣可以参阅:http://blog.csdn.net/sanyuesan0000/article/details/19998727 (打开浏览器,复制url)

这篇博客。BEGIN END的方式,也是从这篇博客中得到启发。只不过他是把BEGIN END用在update中。

②foreach begin end 语句块

我的实现:

批量插入数据(基于Mybatis的实现-Oracle)第13张 insertBatch

 调用方式:

批量插入数据(基于Mybatis的实现-Oracle)第14张 saveBatch(List list)

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

四、java自带的批处理方式

废话不多说,直接上代码

批量插入数据(基于Mybatis的实现-Oracle)第15张 JDBC BATCH

这种批量插入大量数据的方式,性能上最好。但是因为我们小组代码管理所限制,因此这种方式不使用。

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

五、其他方式

现在已经忘了,其他方式到底使用过哪些,但总归是比以上四种效果都更差,所以没什么印象了。

如果各位,还有什么其他更好的批量插入数据的方式,欢迎加入讨论,集思广益。 

以上就是这两天,对在原项目基础上不进行大变动的基础上,提供批处理插入数据的所思所行。

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

后记:

这里吐槽一句:希望大家不要把未经过自己验证的东西,言之凿凿地写到博客中去。

在我做批处理这件事的时候,领导也在参阅网上的博客。其中有一篇博客,说自己在oracle中批量插入数据,采用foreach insert into (field1,field2,...) values (v11,v12,...),(v21,v22,...) ,(v31,v32,...),...也可以。

虽然我明知不行,但是无可奈何还是要去演示给领导看,在oracle中,这种写法确实不适用。

领导问我为何他说可以,我想我也只能回答:他抄别人的博客呗,抄来抄去都不自己实践验证,就想当然地写到博客里。

所以,如果你看完了我这篇分享,希望您也能写个demo验证下,起码可以加深自己的理解。

免责声明:文章转载自《批量插入数据(基于Mybatis的实现-Oracle)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇c# 获取相对路径数据库之ODPS中sql语句指南下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

离群值检测

离群值检测 离群值 outlier:样本中的一个或几个观测值,它们离其他观测值较远,暗示它们可能来自不同的总体。 离群值分类 总体固有变异性的极端表现,这类离群值与样本的其余观测值属于统一总体; 由于试验条件和试验方法的偶然偏离所产生的结果,或产生与观察、记录、计算中的失误,这类离群值与样本中其余观测值不属于统一总体。 数学小知识 方差: 标准差: ​...

项目经验分享

转载自:http://blog.csdn.net/luohuacanyue/article/details/12903189 这篇文章里说的内容,其实都是老生常谈,但是里面有一点我觉得非常有道理,在做完一个项目之后,我通常想的是,这个项目中有哪些不足,而不是——“怎样把这个项目做的更好”,两者看上去没什么区别,其实有很大区别,因为出发点不同。 凡事都应该是...

【华为云动态】华为云携手Google,IBM,SAP等多家知名企业加入CDF,助力软件开发生态发展

美国时间3月12日,开源领导力峰会在加利福尼亚召开,本次峰会由Linux基金会主导。会议期间, CDF (Continuous Delivery Foundation)正式成立。华为云DevCloud代表华为加入CDF,成为Premier 会员,参与CDF 基金会的创立。 据了解,CDF是由Jenkins创始人Kohsuke Kawaguchi 牵头组织的...

springboot使用xml配置dubbo读取yml占位符

约定优于配置是springboot简化配置的思路,其中它提供的自动配置、基于注解配置为我们搭建项目框架带来了很大的便利。 使用springboot的项目跟仅使用spring的项目相比,少了很多xml配置文件,基于自动配置或者使用注解和配置类就可完成大多数配置。 springboot + dubbo搭建微服务工程:(springboot版本2.0.4.REL...

tomcat 配置开启 APR 模式

Tomcat ARP介绍  Tomcat可以使用APR来提供超强的可伸缩性和性能,更好地集成本地服务器技术。APR(Apache Portable Runtime) 是一个高可移植库,它是Apache HTTP Server2.x的核心。   APR有很多用途,包括访问高级IO功能(例如sendfile,epoll和OpenSSL),OS级别功能(随机数生...

iOS安装Git:分布式代码托管----【GIt的使用与安装】【Xcode自带Git使用】【Git与GitHub】

首先,Git不是github,Git和github的关系就像是 英雄联盟和对战游戏平台  其次,Xcode内置了Git,我们可以利用github或者国内的开源中国进行代码托管,直接在Xcode上进行团队协作 客户端(pc/mac)想要和github(码云等托管网站)链接,需要在终端生成用户的SSH公钥,而项目的ssh key和用户的ssh key两处地方有...