Mybatis(二)拓展用法,涉及到一些性能的优化

Mybatis二拓展用法

  • 动态sql
  • 批量操作
    • 批量插入
      • 框架实现的批量插入
      • ExecutorType
      • Foreach
    • 批量更新
    • 批量删除
  • 嵌套查询与延迟加载
  • 分页
  • MyBatis-Plus

动态sql

一般动态标签主要有if标签,用来写一写条件语句

<if test="userId!=null">
   and a.user_id= #{userId}
if>

条件较多的时候使用choose标签

<choose>
   <when test="dbType=='mysql'">
        order by er.money
        limit 1
    when>
    <when test="dbType=='oracle'">
        and rownum = 1
        order by er.money
    when>
choose>

格式化标签trim

select * from user 
<trim prefix="WHERE" prefixoverride="AND |OR">
   <if test="name != null and name.length()>0"> AND name=#{name}if>
  <if test="gender != null and gender.length()>0"> AND gender=#{gender}if>
trim>

prefix:前缀      
prefixoverride:去掉第一个and或者是or
foreach标签,和chosse搭配使用

<choose>
    <when test="list != null and list.size() > 0">
        h.id in
        <foreach collection="list" item="id" index="index" open="(" close=")" separator=",">
            #{id}
        foreach>
    when>
    <otherwise>
        h.id< -99999
    otherwise>
choose>

批量操作

批量插入

这个场景是出现最多的,比如接口啥的。
核心的思路就是,减少数据库交互,控制好一次性插入的记录行数
一般来讲有三种解决方案

框架实现的批量插入

这里就不介绍了,不同公司可能有不同的方法

ExecutorType

设置mybatis的sqlsession的ExecutorType为batch,如果用Jdbc则用executeBatch
Mybatis(二)拓展用法,涉及到一些性能的优化_第1张图片

这里注意的两点是
1.将MyBatis session的executor type 设为Batch,而mybatis的默认执行器类型是Simple,这样的设置大大节约了每次创建新的预处理语句的时间
2.session工厂在获取session实例的时候,传了一个false过去,默认值是true是会自动提交的,这里改为手动提交,避免频繁与数据库交互。
3.此方法的使用,在网上有很多推荐,感兴趣的可以搜一下,有很详细的使用样例。

但是经过我的测试,传入一个size为10000的list,session.commit的执行时间竟然达到了14分钟,很夸张。网上也没找到合适的说法,我只能理解为这只是节约了java层创建PreparedStatement对象的时间,但是commit提交到数据库的时候,执行方式还是将10000条insert去逐步执行。所以导致很慢。

Foreach

最简单也是实测最有效的方法
Mybatis(二)拓展用法,涉及到一些性能的优化_第2张图片
原理就是insert into table(a,b,c) value(1,2,3),insert into table(a,b,c) value(4,5,6)
与insert into table(a,b,c) value(1,2,3)(4,5,6)的区别
如果插入的行足够的多,那么两种方式的效率是有很大差别的
当然,这并不意味着要一次性传入过多的行,太长的话不光会导致效率下降,甚至会报错。
所以这个方法的关键就是如何合理的切割你要传入的list
一个list切割方法:
Mybatis(二)拓展用法,涉及到一些性能的优化_第3张图片
使用很简单,就是看length的大小怎么合理分配,这是网上的一个参考图
Mybatis(二)拓展用法,涉及到一些性能的优化_第4张图片

行数和效率不是一个正比的曲线
但是他的数据量很显然和我们使用的又不太一致,所以我个人测试了几种方式如下
Mybatis(二)拓展用法,涉及到一些性能的优化_第5张图片

总数据量:70115
表行数:12
X轴:70115条数据单次分割大小,单位1000
Y轴:70115条数据插入总共需要的时间,单位秒
由此我们也可以简单的看出来,确实是有一个最低点的,大约就在1W条左右

批量更新

使用场景较少,一般都是逻辑都是放在java中的,不然不利于维护

批量删除

使用场景也较少,删除一般都是通过主键删除

嵌套查询与延迟加载

一般而言,我们很少做单表查询,如果是多表关联查询,比如查询文章的同时查询作者信息,就需要结果里有两张表的字段。这时候有四种处理方案来接受并封装结果。

  1. 用Map来接收,这样是很灵活很动态的,但是java中不利于维护,开发起来也有所不便
  2. 建立一个文章作者表,比如BlogAndAuthorDTO,里面可以封装一些blog和author表的字段,这种方式是比较推荐的,利于后期维护
  3. 如果主要是blog表字段,author只有个别字段,那么在Blog实体类中增加@Transient字段,但是增加的多了容易造成冗余字段,维护混乱。
  4. Blog增加一个Author类型的字段,mybatis用嵌套查询做封装
    我们主要介绍第四种,有两种写法
    第一种,结果嵌套型
 
<resultMap id="BlogWithAuthorResultMap" type="com.gupaoedu.domain.associate.BlogAndAuthor"> 
	<id column="bid" property="bid" jdbcType="INTEGER"/> 
	<result column="name" property="name" jdbcType="VARCHAR"/> 
	 
	<association property="author" javaType="com.gupaoedu.domain.Author"> 
		<id column="author_id" property="authorId"/> 
		<result column="author_name" property="authorName"/> 
	association> 
resultMap>

第二种,查询嵌套型

 
<resultMap id="BlogWithAuthorQueryMap" type="com.gupaoedu.domain.associate.BlogAndAuthor"> 
	<id column="bid" property="bid" jdbcType="INTEGER"/> 
	<result column="name" property="name" jdbcType="VARCHAR"/> 
	<association property="author" javaType="com.gupaoedu.domain.Author" column="author_id" 	select="selectAuthor"/> 
resultMap> 

<select id="selectAuthor" parameterType="int" resultType="com.gupaoedu.domain.Author"> 
	select author_id authorId, author_name authorName from author where author_id = #{authorId} 
select>

第一种好理解,就是一个结果集的封装
第二种其实是分两次查询,第一次查询文章,假设查询一次之后返回结果集10条(一次),然后根据这10条数据再去找对应的作者,再发送10次请求到数据库(N次),这样是损耗数据库性能的
所以就可以使用我们的延迟加载

 
<setting name="lazyLoadingEnabled" value="true"/> 
 <setting name="aggressiveLazyLoading" value="false"/> 
 
<setting name="proxyFactory" value="CGLIB" />

懒加载其实就是这样的
第一次查询,只会查询文章
之后,只有调用到blog.getAuthor()这个方法的时候,才会触发第二次查询,否则的话就偷懒不查询了
原理也很简单,当我们输出blog.getClass()的时候,发现它是一个类似BlogAndAuthor_$$_jvst70_0这种的代理对象,否则的话无法做到调用它的一个方法,就能触发查询的效果的,肯定是做了逻辑处理。
上面setting的配置中可以指定代理的工具

分页

分为逻辑分页和物理分页
逻辑分页其实就是假分页,对性能上没啥改善,只是效果上的改变
物理分页是数据库层面的分页,对性能是有改善的,体现在sql中,就是MySQL会生成 limit 语句,Oracle会生成 rownum 语句,SQL Server会生成 top 语句。常用的工具PageHelper

MyBatis-Plus

它是一款mybatis的增强工具包,增加了通用的crud,条件构造器(java中拼接sql条件)、代码生成器(或者公司自己开发的)等

你可能感兴趣的:(mybatis,mybatis,数据库,java)