MyBatis 从入门到精通
我在CSDN博客写了不少和MyBatis相关的博客,2015年时觉得自己写的太零散,不够系统全面,所以在GitBook创建了一本名为MyBatis最佳实践的开源电子书,当时写好了目录大纲,由于维护好几个开源项目,业余时间几乎都被占用,最终也只写了MyBatis Generator部分,也就是博客中的MyBatis Generator 详解。2016年3月份时,博文视点的孙奇俏编辑和我联系,然后就开始了 MyBatis 相关书籍的编写。
本书的内容和各种实践源自于和广大开发人员的交流,特别感谢大家的建议和帮助!
欢迎大家通过GitHub,使用Issues方式进行交流:
本书中从一个简单的 MyBatis 查询入手,搭建起学习 MyBatis 的基础开发环境。通过全面的示例代码和测试讲解了在 MyBatis XML 方式和注解方式中进行增、删、改、查操作的基本用法,介绍了动态 SQL 在不同方面的应用以及在使用过程中的最佳实践方案。针对 MyBatis 高级映射、存储过程和类型处理器提供了丰富的示例,通过自下而上的方法使读者更好地理解和掌握MyBatis 的高级用法,同时针对 MyBatis 的代码生成器提供了详细的配置介绍。此外,本书还提供了缓存配置、插件开发、Spring、Spring Boot 集成的详细内容。最后通过介绍 Git 和 GitHub 让读者了解MyBatis 开源项目,通过对 MyBatis 源码和测试用例的讲解让读者更好掌握 MyBatis。
除了平台自营外,大家还可以搜索第三方卖家,选择价钱合适的购买。
书中第一章的源码,是一个学习 MyBatis 的基础环境。
书中基本用法、动态SQL、拦截器、高级用法的完整源码。
在 mybatis-spring-boot 项目中引用了本项目。
MyBatis 和 Spring 集成的项目。
MyBatis 和 Spring Boot 集成的项目。
除了以上 4 个项目外,还有 mybatis 源码等内容,可以通过 https://mybatis.io 获取。
全书共11 章,每一章的具体内容如下。
本章先简单介绍了 MyBatis 的发展历史和特点,然后通过一步步的操作搭建了一个学习 MyBatis 的基础环境,这个开发环境也是学习后续几个章节的基础。
本章设定了一个简单的权限控制需求,使用 MyBatis XML 方式实现了数据库中一个表的常规操作。在查询方面,通过根据主键查询和查询全部两个方法让读者在学会使用 MyBatis 查询方法的同时,还深入了解 MyBatis 返回值的设置原理。在增、删、改方面提供了大量详细的示例,这些示例覆盖了MyBatis 基本用法的方方面面。
虽然 XML 方式是主流,但是仍然有许多公司选择了注解方式,因此本章非常适合使用注解方式的读者。本章使用注解方式几乎实现了同XML 方式类似的全部方法,包含许多常用注解的基本用法。对于初学者来说,即使不使用注解方式,通过本章和第2 章的对比也可以对 MyBatis 有更深的了解。
本章详细介绍了MyBatis 最强大的动态 SQL 功能,通过丰富的示例讲解了各种动态 SQL 的用法,为动态 SQL 中可能出现的问题提供了最佳实践方案,还提供了动态 SQL 中常用的OGNL 用法。
本章介绍的MyBatis 代码生成器可以减轻基本用法中最繁重的那部分书写工作带来的压力。通过本章的学习,可以使用代码生成器快速生成大量基础的方法,让大家更专注于业务代码的开发,从枯燥的基础编码中解脱出来。
本章介绍了MyBatis 中的高级结果映射,包括一对一映射、一对多映射和鉴别器映射。通过循序渐进的代码示例让读者轻松地学会使用MyBatis 中最高级的结果映射。本章还通过全面的示例讲解了存储过程的用法和类型处理器的用法。
本章讲解了MyBatis 缓存配置的相关内容,提供了EhCache 缓存和Redis 缓存的集成方法。虽然二级缓存功能强大,但是使用不当很容易产生脏数据。本章针对脏数据的产生提供了最佳解决方案,并且介绍了二级缓存适用的场景。
本章介绍了MyBatis 强大的扩展能力,利用插件可以很方便地在运行时改变MyBatis 的行为。通过两个插件示例让读者初窥门径,结合第11 章的内容可以让读者开发出适合自己的插件。
本章介绍了最流行的轻量级框架Spring 集成MyBatis 的方法,通过一步步操作从零开始配置,搭建一个基本的Spring、Spring MVC、MyBatis 开发环境。
本章介绍了最流行的微服务框架Spring Boot 集成MyBatis 的方法,通过MyBatis 官方提供的starter 可以很方便地进行集成。同时,本章对starter 中的配置做了简单的介绍,可以满足读者对MyBatis 各项配置方面的需要。
本章是一扇通往开源世界的大门,也是一扇通往 MyBatis 源码学习的大门。从 Git 入门到GitHub 入门,读者可以学会使用最流行的分布式版本控制系统和源代码托管服务。通过一段代码让大家了解 MyBatis 中的一部分关键类,通过代码包讲解可以了解MyBatis 每个包中所含的功能。最后通过MyBatis 丰富的测试用例为读者提供更多更有用的学习内容。
foreach 用法SQL语句中有时会使用IN关键字,例如id in (1,2,3)。可以使用${ids}的方式直接获取值,但这种写法不能防止 SQL 注入,想避免 SQL 注入就需要用#{}的方式,这时就要配合使用 foreach 标签满足需求。
foreach 可以对数组、Map 或实现了 Iterable 接口(如 List、Set)的对象进行遍历。数组在处理时会转换为 List 对象进行处理,因此 foreach 遍历的对象可以分为两大类:Iterable 类型和 Map 类型。这两种类型在遍历循环时情况不一样,这一节会通过3个例子来讲解 foreach 的用法。
foreach 实现 in 集合foreach 实现 in 集合(或数组)是最简单和常用的一种情况,下面介绍如何根据传入的用户 id 集合查询出所有符合条件的用户。首先在 UserMapper 接口中增加如下方法。
/**
* 根据用户id集合查询
*
* @param idList
* @return
*/
List selectByIdList(List idList);
在 UserMapper.xml 中增加如下代码。
select id,
user_name userName,
user_password userPassword,
user_email userEmail,
user_info userInfo,
head_img headImg,
create_time createTime
from sys_user
where id in
#{id}
foreach 包含以下属性。
collection:必填,值为要迭代循环的属性名。这个属性值的情况很多。
item:变量名,值为从迭代对象中取出的每一个值。
index:索引的属性名,在集合数组情况下值为当前索引值,当迭代循环的对象是 Map 类型时,这个值为 Map 的key(键值)。
open:整个循环内容开头的字符串。
close:整个循环内容结尾的字符串。
separator:每次循环的分隔符。
collection 的属性要如何设置呢?来看一下 MyBatis 是如何处理这种类型的参数的。
1. 只有一个数组参数或集合参数
以下代码是 DefaultSqlSession 中的方法,也是默认情况下的处理逻辑。
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
StrictMap map = new StrictMap();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap map = new StrictMap();
map.put("array", object);
return map;
}
return object;
}
当参数类型为 Collection 的时候,默认会转换为 Map 类型,并添加一个 key 为 collection 的值(MyBatis 3.3.0版本增加),如果参数类型是 List 集合,那么就继续添加一个 key 为 list 的值(MyBatis 3.2.8及低版本只有这一个key),这样,当collection="list"时,就能得到这个集合,并对它进行循环操作。
当参数类型为 Array 的时候,也会转换成 Map 类型,默认的 key 为 array。当采用如下方法使用数组参数时,就需要把foreach 标签中的 collection 属性值设置为 array。
/**
* 根据用户id集合查询
*
* @param idArray
* @return
*/
List selectByIdList(Long[] idArray);
上面说是数组或集合类型的参数默认的名字,推荐使用@Param来指定参数的名字,这时 collection 就设置为通过@Param注解指定的名字。
2. 有多个参数
第 2 章中讲过,当有多个参数的时候,要使用@Param注解给每个参数指定一个名字,否则在 SQL 中使用参数时就会不方便。因此将collection 设置为 @Param 注解指定的名字即可。
3. 参数是 Map 类型
使用 Map 和使用@Param注解方式类似,将 collection 指定为对应 Map 中的 key 即可。如果要循环所传入的 Map,推荐使用@Param注解指定名字,此时可将 collection 设置为指定的名字,如果不想指定名字,就要使用默认值_parameter。
4. 参数是一个对象
指定为对象的属性名即可。当使用对象内多层嵌套的对象时,使用属性.属性(集合和数组可以使用下标取值)的方式可以指定深层的属性值。
先来看一个简单的测试代码,验证以上说法。
@Test
public void testSelectByIdList(){
SqlSession sqlSession = getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List idList = new ArrayList();
idList.add(1L);
idList.add(1001L);
//业务逻辑中必须校验idList.size() > 0
List userList = userMapper.selectByIdList(idList);
Assert.assertEquals(2, userList.size());
} finally {
//不要忘记关闭sqlSession
sqlSession.close();
}
}
该测试输出的日志如下。
…
在 UserMapper.xml 中添加如下 SQL。
insert into sys_user(
user_name, user_password,user_email,
user_info, head_img, create_time)
values
(
#{user.userName}, #{user.userPassword},#{user.userEmail},
#{user.userInfo}, #{user.headImg, jdbcType=BLOB}, #{user.createTime, jdbcType=TIMESTAMP})
注意:通过 item 指定了循环变量名后,在引用值的时候使用的是属性.属性(如 user.userName)的方式。
针对该方法编写测试如下。
…
这里的 key 作为列名,对应的值作为该列的值,通过 foreache 将需要更新的字段拼在 SQL 语句中。
该 SQL 对应在 UserMapper 接口中的方法如下。
/**
* 通过Map更新列
*
* @param map
* @return
*/
int updateByMap(Map map);
这里没有通过@Param注解指定参数名,因而MyBatis在内部的上下文中使用了默认值_parameter作为该参数的key,所以在XML中就使用了_parameter。编写测试代码如下。
…
测试代码输出日志如下。
…
到这里,foreach 的全部内容就介绍完了,下一节将介绍 bind 的用法。
bind 用法bind 标签可以使用 OGNL 表达式创建一个变量并将其绑定到上下文中。在前面的例子中,UserMapper.xml 有一个selectByUser 方法,这个方法用到了 like 查询条件,部分代码如下。
and user_name like concat('%', #{userName}, '%')
使用 concat 函数连接字符串,在 MySQL 中,这个函数支持多个参数,但在 Oracle 中只支持两个参数。由于不同数据库之间的语法差异,如果更换数据库,有些 SQL 语句可能就需要重写。针对这种情况,可以使用 bind 标签来避免由于更换数据库带来的一些麻烦。将上面的方法改为 bind 方式后,代码如下。
and user_name like #{userNameLike}
bind 标签的两个属性都是必选项,name 为绑定到上下文的变量名,value 为 OGNL 表达式。创建一个 bind 标签的变量后,就可以在下面直接使用,使用 bind 拼接字符串不仅可以避免因更换数据库而去修改 SQL,也能预防 SQL 注入。大家可以根据需求,灵活使用 OGNL 表达式来实现功能,关于更多的 OGNL 常用的表达式,会在 4.7 节中详细介绍。
由衷地感谢大家购买此书,希望大家会喜欢,也希望这本书能够为各位读者带来所希望获得的知识。虽然我已经非常细心地检查书中所提到的所有内容,但仍有可能存在疏漏,若大家在阅读过程中发现错误,在此我先表示歉意。欢迎各位读者对本书的内容和相关源代码发表意见和评论。大家可以通过我的个人邮箱[email protected] 与我取得联系,我会一一解答每个人的疑惑。
关注公众号可以获取更多 MyBatis 相关信息。
No open issues yet, or sync has not completed.