灵活的MyBatis
一、前言
将数据存储到数据库是开发中很重要的一环。曾经有程序员说自己做过最牛逼的事情就是增删改查。确实我们做了很多页面,后太代码写了很多,可是最终都离不开数据库的增删改查。Java有一套自己的JPA标准,而Hibernate很好的实现了这套标准,但为什么会有企业会选择MyBatis进行开发?Hibernate入门的门槛相对较高,而MyBatis上手容易,同时灵活,平常怎么在数据库使用SQL语句,很容易的就可以移植到MyBatis的XML文件里,灵活使得实际开发中更加方便。
二、简单的增删改查
MyBatis中需要将SQL语句封装到XML文件的标签中,无论是简单的增删改查,还是复杂的查询,这种模式都是行之有效的。当然从整体上来看,这种有序地排列SQL语句是一个非常好的结果,在理想的情况下,并没有问题。然而实际上,有的项目会用几十个字段,一个单一业务模块背后的SQL代码可能达到上千行,同时有可能没有注释,这样子想找一条已经存在有合用的SQL语句是非常麻烦的事情,同时也很容易造成重复编写相同、相似SQL语句的情况。
比如,已经有一条SQL语句获取没有被删除的User
<select id="getUser" resultType="User">
SELECT * FORM T_USER WHERE DELETE_FLAG = '0'
</select>
如果代码量太大,同时接口方法的命名信息抽象,又没有写任何注释的情况下,有可能会产生相似的语句
<select id="getCancelUser" resultType="User">
SELECT * FROM T_USER WHERE DELETE_FLAG = '1'
</select>
一个是获取已经登记但没有注销的所有用户,一个是获取所有已经注销了的用户。看上去不可能产生这种情况,在上千行代码的情况下,就有可能会产生,毕竟接口抽象,又没有注释。
因此,对于这种简单SQL语句,可以使用注解的方法,使抽象的接口"形象化“
@Select("SELECT * FROM T_USER WHERE DELETE_FLAG = '0'")
public User getUser();
当你的团队成员在寻找相似语句的时候,就可以很容易地注意到这条SQL语句,而不是这表述含糊的方法名。这个时候,就不需要写一条新的SQL语句,只需要在原来的基础上进行修改就可以了
@Select("SELECT * FROM T_USER WHERE DELETE_FLAG = #{deleteFlag}")
public User getUser(@Param("deleteFlag")String deleteFlag);
这样同一条SQL语句,只要传不同的值就可以了。@Param是参数的注解,一般情况下,是可以不加这个注解的,MyBatis可以自动封装。
类似地,还有@Insert、@Update、@Delete注解,使用基本雷同。
三、动态SQL
在进行数据库操作的时候,我们通常传入对象来进行增删改查,但是如果传入的对象在某些时候没有值,那么我们通过动态标签就可以避免重复编写相似的SQL语句
1、<if>与<where>
//public List<Blog> findActiveBlogLike(Blog blog)
<select id="findActiveBlogLike" parameterType="Blog" resultType="Blog">
SELECT * FROM BLOG
<WHERE>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</WHERE>
</select>
我们可以通过<if>标签,判断传入的对象是否存在值,进而动态改变查询的SQL语句。如果所有的条件均为空,那么就会出现SELECT * FROM BLOG WHERE 这样的SQL语句,这个时候会报错,当然可以改为SELECT * FROM BLOG WHERE 1=1。同时也可以引用<where>标签,当所有的条件均不存在的时候,这个where也会被自动去掉
2、<foreach>
//public List<Post> selectPostIn(List<String> list)
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
当我们需要查询的SQL语句包含in 的时候,我们可以通过<foreach>来遍历实现。
3、<set>
<update id="updateAuthorIfNecessary"
parameterType="domain.blog.Author">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio},</if>
</set>
where id=#{id}
</update>
进行更行操作的时候,传入的对象的各个字段不一定都有值,这个时候,可以使用<if>标签来进行动态列举,但这个时候会产生一个问题,那就是条件后面的“,”逗号,为了避免报错,这里可以引入<set>标签,即使最后一个条件后面有逗号,也不会报错
动态标签还有其他的,详细可以参考官方文档[1]。
四、缓存[2]
对于一些常用的查询,不可能每一次都从数据库里头拿,特别是那些相对固定,同时数据量又比较大的查询。这个时候缓存显得比较重要。MyBatis有自己的缓存机制,也可以与Ehcache整合[3],当然最好是使用Redis
五、后言
MyBatis是一个很灵活的持久层框架,本文旨在阐述MyBatis的基本使用,以及日常优化配置。同时本文也是这一系列最后一篇文章。本系列五篇文章旨在指出理论学习与实际应用当中的差异,既非入门教程,也非解决方案。
--2018.10.08增补--
框架具有时代性。在SSM之前,是S2SH的时代,在哪个时代,S2SH是非常优秀的框架,对比起传统的JDBC和Servlet来说。上个世纪50年代,拿着“大哥大”打电话是非常先进的,毕竟当时很少人可以用到。本世纪初,诺基亚的手机相比起“大哥大”要先进许多。到今天2018年,人们都是用着代用指纹识别、可拍照、可上网的智能手机。技术在迭代,时代在改变。
Reference:
[1] 官方中文网,http://www.mybatis.org/mybatis-3/zh/index.html
[2] 小秋蜀黍, mybatis缓存文件的配置, https://blog.csdn.net/sinat_32133675/article/details/76691009
[3] 落叶枫桥, MyBatis笔记——EhCache二级缓存, https://www.cnblogs.com/pwc1996/p/4839133.html