Mybatis使用陷阱

421 查看

缓存不是基于行的

“缓存并不是基于行的”的意思就是,mybatis缓存的粒度是全部查询结果,而不是查询结果的每行,这也就意味着每次查询,就只有一份缓存,而不是有几行就有几分缓存。

这点和hibernate很不同,hibernate的缓存是基于每个对象的,即查询出来的有几个对象,那就有几份缓存。

mybatis无法像hibernate给每个对象做缓存,主要原因是mybatis非常自由,能够配置任意的返回结果类型,这也就是说返回的结果并不一定都有主键,如此一来也就没有办法标识某一行数据和哪个返回结果对应,而hibernate是强制你所映射的每个类都要有主键的。

参考文档:http://www.mybatis.org/mybatis-3/sqlmap-xml.html#cache

缓存默认没有失效时间

“缓存默认没有失效时间”的意思是如果我们直接在数据库里修改数据,那么每次用mybatis查询的时候,使用的还是上一次的缓存结果,且这份缓存一直有效,除非我们通过mapper调用了update、delete、insert方法,这些方法会使缓存失效。解决办法很简单,就是在使用<cache />的时候一定要写上flushInterval属性。

参考文档:http://www.mybatis.org/mybatis-3/sqlmap-xml.html#cache

使用Partial Auto-mapping后,自动去重问题

Partial Auto-mapping的意思是你对ResultMap只提供了部分字段的配置而不是全部字段,但是如果你的这个ResultMap没有设置ID,也就是主键,那么mybatis将会根据你提供的这一部分字段配置来判断两行数据是否重复,并且会将重复的去掉。

实际上关于id的作用在官方文档中很隐晦的提到过了:见http://www.mybatis.org/mybatis-3/sqlmap-xml.html#Result_Maps的id & result部分。

比如下面这个配置启用了autoMapping,且部分配置了property的映射。在这种情况下,如果查询出两条记录了,而这两条记录的task_key的值是一样的时候,mybatis就会认为是同一条,最终返回给你一个AuditLog

<resultMap id="AuditLog" type="AuditLog" autoMapping="true">
   <result column="task_key" property="taskKey"/>
</resultMap>

解决办法有两个:

  1. 不配置property的映射:

    <resultMap id="AuditLog" type="AuditLog" autoMapping="true">
    </resultMap>
  2. 不使用automapping:

    <resultMap id="AuditLog" type="AuditLog">
        <result column="task_key" property="taskKey"/>
        <result column="result" property="result"/>
        <result column="when" property="when"/>
        <result column="name_zh" property="nameZh"/>
        <result column="name_en" property="nameEn"/>
        <result column="remark" property="remark"/>
    </resultMap>

参考文档:http://www.mybatis.org/mybatis-3/sqlmap-xml.html#Auto-mapping

aggressiveFetch的问题

在使用mybatis懒加载特性的时候有一点需要注意,就是要把aggressiveFetch设置为false

根据官方文档,当设置为true的时候,如果你get了懒加载属性,那么其他懒加载属性也会一并加载。

但实际情况时,当设置了true的时候,如果你get了任一属性,那么所有懒加载属性也会一并加载。