首先,我们还是先来回顾一下 MyBatis 本身吧。
1.1 框架概述论概述,肯定还是找最权威的官方文档为好。打开 MyBatis 的官方文档 mybatis – MyBatis 3 | 简介,在最醒目的位置有官方对于 MyBatis 给出的定义:
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
三句话,把 MyBatis 的核心功能和使用特性都概括了出来,这些内容在我们学习 MyBatis 基础时都已经学过了,这里我们不再对概述的内容详细展开,各位快速过一遍即可。
1.2 MyBatis历史MyBatis 的历史,估计各位都只是了解到它的前身是 iBATIS ,之前是 Apache 的,后来迁移到 GoogleCode 又到 GitHub 上,仅此而已。这里小册想多跟各位聊一点历史,以及它与 Hibernate 的关系。
1.2.1 MyBatis与Hibernate的起源时间相当
首先,我们先来解释一个可能部分小伙伴的印象中的误区:MyBatis 的出现是为了干掉笨重的 Hibernate 。
从最早的起源来看,MyBatis 最初的创建时间是 2001 年,第一个发行版( JPetStore )是 2002 年 7 月,而 Hibernate 的第一个发行版是 2001 年 11 月。所以从历史上看,MyBatis 跟 Hibernate 本就是两个独立互不干涉的工程,并没有谁要干掉谁的意思,两个框架的侧重点和关注点不一样,使用的场景也会有差别。
1.2.2 MyBatis的前身-iBATIS
好了我们说回 MyBatis 的前身 iBATIS ,当初 iBATIS 的创始人 Clinton Begin 最先制作的产品并不是 iBATIS-DAO ,而是着手于密码软件的相关解决方案。随后 iBATIS 的第一个产品 Secrets 就诞生了。
然而发行了 Secrets 不久,Clinton Begin 及其团队决定转型关注 Web 和其他相关的技术,也在接下来的一年中发布了两个工具( Axle web 与 Lookout )。不过最重要的转折点,是在 Microsoft 发布了一个文档,声称 .NET 有十倍于 J2EE 的速度和 4 倍的生产效率后,Clinton Begin 看着不爽,就对标 PetStore 的需求搞了一个 JPetStore 。后来经过时间的考验,大家发现 Java 不仅比 .NET 更有生产效率,同时 JPetStore 比 Microsoft 的 PetStore 实现拥有更好的架构。
JPetStore 的发行引起了当时开发界程序猿们的关注,大家对 JPetStore 的持久层设计很感兴趣,于是后来 JPetStore 的持久层部分逐渐抽取打包,进而发展成当时的 iBATIS 。
2004 年 11 月,iBATIS 2.0 发布,Clinton Begin 将 iBATIS 与代码一同捐献给了 Apache ,自此成为 Apache 开源组织下的一个子项目。
1.2.3 从iBATIS到MyBatis
2010 年 5 月,Clinton Begin 决定将整个 iBATIS 项目团队迁移至 GoogleCode ,并在 2010 年 6 月完成迁移。那时正值 iBATIS 3.0 版本发布,Clinton Begin 决定给新版本赋予新的名字:MyBatis 。后来,到了 2013 年 11 月,MyBatis 的代码迁移至 GitHub ,一直持续到现在。(这部分是我们比较熟悉的历史)
1.3 MyBatis的整体架构从整体上讲,MyBatis 的整体架构可以分为三层:
- 接口层:SqlSession 是我们平时与 MyBatis 完成交互的核心接口(包括后续整合 Springframework 后用到的 SqlSessionTemplate );
- 核心层:SqlSession 执行的方法,底层需要经过配置文件的解析、SQL 解析,以及执行 SQL 时的参数映射、SQL 执行、结果集映射,另外还有穿插其中的扩展插件;
- 支持层:核心层的功能实现,是基于底层的各个模块,共同协调完成的。
后续的章节中,小册会慢慢展开这些内容,现在只是有一个整体的认识即可。
1.4 MyBatis与Hibernate的对比下面我们来回顾一下 MyBatis 与 Hibernate 的对比,这个问题一般面试中会被问到,小册尽可能多的列一些对比指标,小伙伴可根据自己的理解,组织语言进行总结。
| 对比指标 | MyBatis | Hibernate |
|---|---|---|
| 类型 | 半自动,半ORM (允许用 Map ) | 全自动 ORM (只能用实体类) |
| 中心 | SQL(一切 Mapper 里都是 SQL ) | 对象关系(一切操作都围绕对象关系) |
| SQL 优化 | 容易(直接修改 SQL 即可) | 困难(修改 SQL 后还需要转换为 HQL ,如果直接上 SQL 则会破坏封装) |
| 缓存机制 | 一般(管理不慎会出现脏数据) | 完善(基于 ORM 的对象管理机制,出现脏数据会给出提示) |
| 数据库可移植性 | 不好(切换数据库需要重新写 SQL ) | 好(可配置数据库类型自动切换生成的 SQL ) |
| 日志打印体系 | 很有限(只能打印基本日志及交互) | 完善( SQL 记录、关系异常、优化警告、缓存提示、脏数据警告等) |
| 开发效率、工作量 | 效率相对低,工作量多 | 开发效率相对高,工作量少 |
| 学习成本 | 较低(需要学习的内容相对少) | 高(需要额外学习 JPA 、HQL 、QBC 、抓取策略等) |
| 适用场景 | 比较容易出现复杂 SQL 的项目 | 复杂查询很少的项目 |
接下来,我们来回顾一下纯 MyBatis 的工程环境搭建。
本小册使用的 MyBatis 版本为 3.5.5 ,数据库采用 MySQL 5.7 。
2.1 数据库初始化首先我们先来初始化一个数据库。创建数据库的方式很简单啦,一条 SQL 就可以搞定:
CREATE DATAbase mybatis;
然后,创建一个 “部门” 表:
CREATE TABLE tbl_department ( id varchar(32) NOT NULL, name varchar(32) NOT NULL, tel varchar(18) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
接下来,给这张表初始化几条数据:
INSERT INTO tbl_department(id, name, tel) VALUES ('00000000000000000000000000000000', '全部部门', '-');
INSERT INTO tbl_department(id, name, tel) VALUES ('18ec781fbefd727923b0d35740b177ab', '开发部', '123');
INSERT INTO tbl_department(id, name, tel) VALUES ('53e3803ebbf4f97968e0253e5ad4cc83', '测试产品部', '789');
INSERT INTO tbl_department(id, name, tel) VALUES ('ee0e342201004c1721e69a99ac0dc0df', '运维部', '456');
2.2 Maven工程与依赖导入
接下来是工程的创建。Maven 工程的创建咱就不多说了,前面几章咱都是基础回顾,所以小册起的工程名就叫 mybatis-01-basic 啦。
依赖的话,我们导入 MyBatis 的 3.5.5 版本,以及 MySQL 的驱动,log4j 的日志包:
org.mybatis mybatis3.5.5 mysql mysql-connector-java5.1.47 log4j log4j1.2.17
当然,不要忘记加 Maven 编译插件,使工程的整体编译版本升到 1.8 :
2.3 log4j.propertiesorg.apache.maven.plugins maven-compiler-plugin3.8.1 1.8 1.8 UTF-8
导完依赖,咱先把 log4j 的配置文件搞定了,这家伙的写法千篇一律,没啥好说的,直接复制粘贴就完事了。
log4j.rootCategory=debug, ConSOLE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, ConSOLE
# ConSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.ConSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Encoding=UTF-8
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m n
2.4 MyBatis全局配置文件
OK 接下来该编写 MyBatis 的全局配置文件了。这个配置文件的命名,有叫 SqlMapConfig.xml 的,有叫 mybatis.xml 的,这个无所谓,看各位编码命名习惯就好,小册这里就叫 mybatis-config.xml 了:
快速看一眼上面的内容,主要包含 MyBatis 运行环境的配置、数据源的配置,以及 mapper.xml 映射文件的加载。
2.5 mapper.xml编写有了配置文件后,下面我们来编写一个 mapper.xml 的 SQL 映射文件:
select * from tbl_department
这里面的声明都非常简单了吧,我们快速编写一下就 OK 。
2.6 实体类的创建光有 mapper.xml 还不够,我们说一个实体表要对应一个实体类呢,下面我们把 Department 实体类也编写出来:
public class Department {
private String id;
private String name;
private String tel;
// getter setter toString equals hashcode
}
OK ,这些搞完,基本的代码也就都编写完了。
2.7 编写测试运行下面我们就来编写一个最最简单的测试运行代码,利用 SqlSessionFactoryBuilder 加载配置文件,生成 SqlSessionFactory ,然后从 SqlSessionFactory 中获取 SqlSession ,进而调用 mapper.xml 中的 statement :
public class MyBatisApplication1 {
public static void main(String[] args) throws Exception {
InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml);
SqlSession sqlSession = sqlSessionFactory.openSession();
List departmentList = sqlSession.selectList("departmentMapper.findAll");
departmentList.forEach(System.out::println);
}
}
运行 main 方法,控制台可以成功打印出数据库中刚刚初始化的几条数据:
Department{id='00000000000000000000000000000000', name='全部部门', tel='-'}
Department{id='18ec781fbefd727923b0d35740b177ab', name='开发部', tel='123'}
Department{id='53e3803ebbf4f97968e0253e5ad4cc83', name='测试产品部', tel='789'}
Department{id='ee0e342201004c1721e69a99ac0dc0df', name='运维部', tel='456'}
说明基本的代码已经成功编写完成了。



