1 什么是 MyBatis

MyBatis 是 Apache 开源的项目,是一个基于 Java 持久层的框架。

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO 为数据库中的记录。

MyBatis 官方文档:MyBatis – MyBatis 3 | 简介

2 一些基本概念

MyBatis 是一个基于 Java 的持久层 / ORM 框架,所以我们在学习之前,先来了解一下如下基本概念。

2.1 什么是“持久化”

持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML 数据文件中等,但是一般都会存放在关系型数据库中如:MySQL、Oracle 等。

2.2 什么是“持久层”

持久层(Persistence Layer),即专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联。比如我们的 pojo 层、Dao 层和 Service 层的关联。

2.3 什么是“ORM”

ORM 即 Object-Relationl Mapping,意思为对象关系映射。它用于实现面向对象编程语言的类型和关系型数据库类型之间的相互转换。简单的说,ORM 是通过描述对象和数据库之间映射的元数据,将程序中的对象与关系数据库相互映射,到时候我们在具体的操作数据库的时候,就不需要再去和复杂的 SQL 语句打交道,只要像平时操作对象一样操作它就可以了。但是从前面的描述可知,我们的 MyBatis 是需要与 SQL 打交道的,所以我们认为 MyBatis 是一个半自动化的 ORM 框架。

在 Java 中典型的 ORM 中有:

  • JPA:JPA 全称 Java Persistence API,即 Java 持久化 API,是 sun 公司推出的一套基于 ORM 的规范,内部由一系列的接口和抽象类构成。JPA 通过 JDK 5.0 注解或 XML 描述对象-关系表的映射关系,是 Java 自带的框架。
  • Hibernate:全自动的 ORM 框架,强大、复杂、笨重、学习成本较高。Hibernate 除了作为 ORM 框架之外,它也是一种 JPA 实现。
  • MyBatis:半自动的 ORM 框架,强大,简单,灵活,学习成本较低。MyBatis 提供了自定义 SQL,这样开发者将主要精力放在 SQL 上就行了。

之所以要做持久化和使用 ORM 设计,因为持久化解决了数据的存储问题,ORM 解决的主要是对象关系的映射的问题。在目前的企业应用系统设计中,都是以 MVC 为主要的系统架构模式 (MVC 即 Model(模型)- View(视图)- Control(控制))。MVC 中的 Model 包含了复杂的业务逻辑和数据逻辑,以及数据存取机制等(如 JDBC 的连接、SQL 生成和 Statement 创建、还有 ResultSet 结果集的读取等)。将这些复杂的业务逻辑和数据逻辑分离,以将系统的紧耦合关系转化为松耦合关系(即解耦合),是降低系统耦合度迫切要做的,也是持久化要做的工作。MVC 模式实现了架构上将表现层(即 View)和数据处理层(即 Model)分离的解耦合,持久化的设计则实现了数据处理层内部的业务逻辑和数据逻辑分离的解耦合。而 ORM 作为持久化设计中的最重要也最复杂的技术,也是目前业界热点技术。

一般情况下,一个持久化类和一个表对应,类的每个实例对应表中的一条记录,类的每个属性对应表的每个字段。

下面我们将关系数据中的表记录映射成为对象,以对象的形式展现,这样程序员可以把对数据库的操作转化为对对象的操作。

image

因此 ORM 的目的是为了方便开发人员以面向对象的思想来实现对数据库的操作。

ORM 的方法论基于三个核心原则:

  • 简单:以最基本的形式建模数据。
  • 传达性:数据库结构被任何人都能理解的语言文档化。
  • 精确性:基于数据模型创建正确标准化了的结构。

什么是 DAO
Data Access Objects(DAOs) : 数据访问,对数据库执行增删改查。

3 为什么使用 MyBatis

我们以前在没有 ORM 框架的情况下,如果你要开发一个 Web 应用程序的话,你就必须要使用传统的 JDBC 代码来操作数据库,我们除了需要自己提供 SQL 外,还必须操作 Connection、Statment、ResultSet 等,不仅如此,为了访问不同的表,不同字段的数据,我们需要些很多雷同模板化的代码,而这些代码写起来往往是重复的,写起来又繁琐又枯燥。

我们下面来分析一下使用传统 JDBC 的缺陷,先看如下代码:

public class SqlConnection {
	 public static void main(String[] args) {
		 //定义数据库连接
		 Connection con = null;
		 //定义数据库语句
		 PreparedStatement ps = null;
		 //定义返回结果集
		 ResultSet rs= null;
		 try {
			 //加载数据库驱动
			 Class.forName("com.mysql.cj.jdbc.Driver");
			 //定义MySQL URL,因为这里有的长所以在这里定义了
			 String url = "jdbc:mysql://localhost:3306/user?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8";
			 //获取连接
			 con = DriverManager.getConnection(url,"root","root");
			 //定义SQL语句,?表示占位符
			 String sql = "select * from t_user where username = ?";
			 //获取编译处理的statement
			 ps = con.prepareStatement(sql);
			 //设置SQL参数
			 ps.setString(1,"唐浩荣");
			 //执行SQL语句查询,并且返回结果集
			 rs = ps.executeQuery();
			 //遍历结果集
			 while (rs.next()){
				 System.out.println(rs.getInt("id")+"--"+rs.getString("username")+"--"+rs.getInt("age"));
				 }
			 } catch (ClassNotFoundException e) {
				 e.printStackTrace();
			 } catch (SQLException e) {
				 e.printStackTrace();
			 }finally {
				 //关闭数据库连接(三个写一起方便0.0)
				 try {
					 rs.close();
					 ps.close();
					 con.close();
				 } catch (SQLException e) {
					 e.printStackTrace();
				 }
		 }
	 }
}

通过上面的一段 JDBC 连接数据代码,我们看有哪些不好的地方:

  • 在创建 Connection 对象的时候,存在硬编码问题。也就是直接把连接数据库的信息写死,如果需要连接不同的数据库则要更改配置,不方便后期维护。
  • 在使用 PreparedStatement 对象执行 SQL 语句的时候同样存在硬编码问题。将 SQL 语句硬编码到 Java 代码中,如果 SQL 语句修改,需要重新编译 Java 代码,不利于系统维护。
  • 向 PreparedStatement 中设置参数,对占位符号位置和设置参数值,硬编码在 Java 代码中,不利于系统维护。
  • 从 ResutSet 中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,如果表的字段修改了则代码也需要修改,不利于系统维护。
  • 每次在进行一次数据库连接后都会创建和关闭数据库连接,频繁的开启/关闭数据连接会造成数据库资源浪费,影响数据库性能。
  • 缓存做的很差,如果存在数据量很大的情况下,这种方式性能特别低。

所以通过上面的分析,我们知道为什么要使用 MyBatis 了吧。在使用了 MyBatis 之后,只需要提供 SQL 语句就好了,其余的诸如:建立连接、操作 Statment、ResultSet,处理 JDBC 相关异常等等都可以交给 MyBatis 去处理,我们的关注点于是可以就此集中在 SQL 语句上,关注在增删改查这些操作层面上。并且 MyBatis 支持使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs (Plain Old Java Objects,即普通的 Java 对象) 映射成数据库中的记录。

简单的说一下 MyBatis 相对 JDBC 的优势:

  • MyBatis 是把连接数据库的信息都是写在配置文件中,因此不存在硬编码问题,方便后期维护。
  • MyBatis 执行的 SQL 语句都是通过配置文件进行配置,不需要写在 Java 代码中。
  • MyBatis 的连接池管理、缓存管理等让连接数据库和查询数据效率更高。

4 MyBatis 的特点及优缺点

特点:

  • MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
  • MyBatis 封装了底层 JDBC API 的调用细节,并能自动将结果集转换成 Java Bean 对象,大大简化了 Java 数据库编程的重复工作。
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  • MyBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的实体映射成数据库中的记录。
  • MyBatis 把 SQL 语句从 Java 源程序中独立出来,放在单独的 XML 文件中编写,给程序的维护带来了很大便利。
  • MyBatis 需要程序员自己去编写 SQL 语句,程序员可以结合数据库自身的特点灵活控制 SQL 语句,因此能够实现比 Hibernate 等全自动 ORM 框架更高的查询效率,能够完成复杂查询。

优点

  • 简单易学,MyBatis 本身就很小且简单,整个源代码大概 5MB 左右。并且没有任何第三方依赖,简单实用只要几个 Jar 包+配置几个 SQL 映射文件,而且有官方中文文档,可以通过官方文档轻松学习。
  • 使用灵活,易于上手和掌握。相比于 JDBC 需要编写的代码更少,减少了 50%以上的代码量。
  • 提供 XML 标签,支持编写动态 SQL,满足不同的业务需求。
  • SQL 写在 XML 里,便于统一管理和优化,同时也解除 SQL 与程序代码的耦合。使系统的设计更清晰,更易维护,更易单元测试。SQL 和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的 ORM 字段关系映射。
  • 提供对象关系映射标签,支持对象关系组建维护。

缺点

  • SQL 语句的编写工作量较大,尤其在表、字段比较多的情况下,对开发人员编写 SQL 的能力有一定的要求。
  • SQL 语句依赖于数据库,导致数据库不具有好的移植性,不可以随便更换数据库。

总体来说,MyBatis 是一个非常优秀和灵活的数据持久化框架,适用于需求多变的互联网项目,也是当前主流的 ORM 框架。

5 MyBatis 下载

MyBatis 下载地址

下载后,除了必要的 Jar 包外,还有一个官方的 pdf 文档。

6 MyBatis 和 Hibernate 的区别

MyBatis 和 Hibernate 都是一款非常受欢迎的持久化框架,那么 MyBatis 和 Hibernate 二组之间有哪些区别呢?

下面我们来看一下,因为这个问题面试很可能会问到。

①、开发方面:

  • Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。
  • MyBatis 属于半自动 ORM 映射工具,MyBatis 在查询关联对象或关联集合对象时,需要手动编写 SQL 来完成,所以,称之为半自动 ORM 映射工具。不过 MyBatis 可以通过 XML 或注解方式灵活配置要运行的 SQL 语句,并将 Java 对象和 SQL 语句映射生成最终执行的 SQL,最后将 SQL 执行的结果再映射生成 Java 对象。

②、底层方面:

  • Hibernate 的底层则是 JPA 规范的实现。
  • MyBatis 的底层封装了 JDBC 的代码。

③、SQL 优化方面:

  • Hibernate 自动生成 SQL, 有些语句较为繁琐,会多消耗一些性能。
  • MyBatis 手动编写 SQL,可以避免不需要的查询,提高系统性能。

④、学习成本方面:

  • Hibernate 的学习门槛高,要精通门槛更高,而且怎么设计 O/R 映射,在性能和对象模型之间如何权衡,以及怎样用好 Hibernate 需要具有很强的经验和能力才行。
  • MyBatis 的学习门槛低,简单易学,程序员只需要把重心放在写原生态 SQL 上即可,可严格控制 SQL 执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。

⑤、对象管理方面

  • Hibernate 是完整的对象/关系映射的框架,对象/关系映射能力极强,开发工程中,无需过多关注底层实现,只要去管理对象即可;而且数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用 Hibernate 开发可以节省很多代码,提高效率。
  • MyBatis 需要自行管理映射关系;而且 MyBatis 无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套 SQL 映射文件,工作量大。

⑥ 日志系统方面:

  • Hibernate 日志系统非常健全,涉及广泛,包括:SQL 记录、关系异常、优化警告、缓存提示、脏数据警告等。
  • MyBatis 则除了基本记录功能外,功能薄弱很多。

⑦、缓存方面

  • 相同点:

Hibernate 和 MyBatis 的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。

  • 不同点:

Hibernate 的二级缓存配置在 SessionFactory 生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。如果使用二级缓存时如果出现脏数据,系统会报出错误并提示。

MyBatis 的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且 MyBatis 可以在命名空间中共享相同的缓存配置和实例,通过 Cache-ref 来实现。

⑧、各一句话总结它们:

  • MyBatis:小巧、方便、高效、简单、直接、半自动化。比喻:机械工具,使用方便,拿来就用,但工作还是要自己来作,不过工具是活的,怎么使由我决定。
  • Hibernate:强大、方便、高效、复杂、间接、全自动化。比喻:智能机器人,但研发它(学习、熟练度)的成本很高,工作都可以摆脱他了,但仅限于它能做的事。

最后,不管你使用哪个持久化框架,它们都有它们各自的特点。总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

参考链接:MyBatis 与 Hibernate 区别

7 MyBatis 的重要组件

MyBatis 封装了 JDBC 的代码,我们来分析 MyBatis 给我们的一些重要组件。

image

我们从上往下看,MyBatis 中的一些重要组件如下::

  • MyBatis 的配置文件:SqlMapConfig. Xml 是 MyBatis 的全局配置文件,主要配置数据源、事务、加载映射文件等,它的名称可以是任意 (最好见名知意)。Mapper. Xml 主要是配置 Statement 的相关信息,如 SQL 语句。
  • SqlSessionFactoryBuilder:会根据 XML 配置或是 Java 配置来生成 SqlSessionFactory 对象. 采用建造者模式。
  • SqlSessionFactory:用于生成 SqlSession,可以通过 SqlSessionFactory. OpenSession () 方法创建 SqlSession 对象。使用工厂模式。
  • SqlSession:相当于 JDBC 中的 Connection 对象,可以用 SqlSession 实例来直接执行被映射的 SQL 语句,也可以获取对应的 Mapper。
  • Executor:MyBatis 中所有的 Mapper 语句的执行都是通过 Executor 执行的。(Mapper:由 XML 文件和 Java 接口组成,根据 XML 中配置的映射信息执行对应的 SQL 语句并返回执行结果。)
  • Mapper 接口:数据操作接口也就是通常说的 DAO 接口,要和 Mapper 配置文件中的方法一一对应,也就是必须和 Mapper. Xml 中的增删改查标签 Id 一致。
  • Mapper 配置:用于组织具体的查询业务和映射数据库的字段关系,可以使用 XML 格式(Mapper. Xml)或 Java 注解格式来实现。
  • MappedStatement:作用是封装了 Statement 的相关信息,包括 SQL 语句、输入参数和输出结果等等。

8 MyBatis 执行流程简单说明

  1. 首先是加载 MyBatis 的全局配置文件,随后会加载 SQL 映射文件或者是注解的相关 SQL 内容。
  2. 创建会话工厂,MyBatis 通过读取配置文件的信息来构造出会话工厂(SqlSessionFactory)。
  3. 创建会话,根据会话工厂,MyBatis 就可以通过它来创建会话对象(SqlSession),会话对象是一个接口,该接口中包含了对数据库操作的增、删、改、查方法。
  4. 创建执行器,因为会话对象本身不能直接操作数据库,所以它使用了一个叫做数据库执行器(Executor)的接口来帮它执行操作。
  5. 封装 SQL 对象,在这一步,执行器将待处理的 SQL 信息封装到一个对象中(MappedStatement),该对象包括 SQL 语句、输入参数映射信息(Java 简单类型、HashMap 或 POJO)和输出结果映射信息(Java 简单类型、HashMap 或 POJO)。
  6. 操作数据库,拥有了执行器和 SQL 信息封装对象就使用它们访问数据库了,最后再返回操作结果,结束流程。