1、什么是MyBatis?

一款优秀的持久化层的ORM框架,它支持动态SQL以及对结果集进行映射。MyBatis的底层操作封装了JDBC的API,MyBatis的工作原理以及核心流程与JDBC的使用步骤一脉相承,MyBatis的核心对象(SqlSession,Executor)与JDBC的核心对象(Connection,Statement)相互对应。

ORM(Object Relational Mapping,对象关系映射)是一种数据持久化技术,它在对象模型和关系型数据库之间建立起对应关系,并且提供了一种机制,通过 JavaBean 对象去操作数据库表中的数据。

2、MyBatis的工作原理?

JDBC有四个核心对象:
(1)DriverManager,用于注册数据库连接
(2)Connection,与数据库连接对象
(3)Statement/PrepareStatement,操作数据库SQL语句的对象
(4)ResultSet,结果集或一张虚拟表

而MyBatis也有四大核心对象:
(1)SqlSession对象,该对象中包含了执行SQL语句的所有方法。类似于JDBC里面的Connection 。
(2)Executor接口,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。类似于JDBC里面的Statement/PrepareStatement。
(3)MappedStatement对象,该对象是对映射SQL的封装,用于存储要映射的SQL语句的id、参数等信息。
(4)ResultHandler对象,用于对返回的结果进行处理,最终得到自己想要的数据格式或类型。可以自定义返回类型。

MyBatis的工作原理如下图所示:

(1)读取MyBatis的配置文件。mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息。

(2)加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。

(3)构造会话工厂。通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory。

(4)创建会话对象。由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。

(5)Executor执行器。MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。

(6)MappedStatement对象。在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息。

(7)输入参数映射。输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程。

(8)输出结果映射。输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。

 

3、MyBatis 配置文件

MyBatis的配置文件包含了影响MyBatis行为的信息。文档的结构如下:
1、顶层configuration 配置
2、properties属性

这些属性都是可外部配置且可动态替换的,既可以在典型的Java属性文件中配置,亦可通过properties元素的子元素来传递。
可以在CLASSPATH 中增加一个db.properties 的Java属性文件。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis
username=root
Password=root
在配置文件中配置<properie.../>属性:
<properties resource="db.properties"/>
其中的属性就可以在整个配置文件中使用来替换需要动态配置的属性值。
<dataSource type="POOLED">
<property name="driver" value="${driver} "/>
<property name="url" value="${url}"/>
<property name="username" value="${username} "/
<property name="password" value="${password} "/>
</dataSource>
driver、url、username 和password属性将会由db.properties文件中对应的值来替换。这样就为配置提供了诸多灵活选择。

3、settings设置

4、typeAliases类型命名

5、typeHandlers类型处理器

6、objectFactory对象工厂

7、plugins插件

8、environments环境
9、environment环境变量
10、transactionManager事务管理器
11、dataSource数据源
12、databaseIdProvider数据库厂商标识
13、mappers映射器

具体的xml配置文件如下所示:

复制代码
 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE configuration
 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4 "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <!-- 配置文件的根元素 -->
 6 <configuration>
 7     <!-- 属性:定义配置外在化 -->
 8     <properties></properties>
 9     <!-- 设置:定义mybatis的一些全局性设置 -->
10     <settings>
11        <!-- 具体的参数名和参数值 -->
12        <setting name="" value=""/> 
13     </settings>
14     <!-- 类型名称:为一些类定义别名 -->
15     <typeAliases></typeAliases>
16     <!-- 类型处理器:定义Java类型与数据库中的数据类型之间的转换关系 -->
17     <typeHandlers></typeHandlers>
18     <!-- 对象工厂 -->
19     <objectFactory type=""></objectFactory>
20     <!-- 插件:mybatis的插件,插件可以修改mybatis的内部运行规则 -->
21     <plugins>
22        <plugin interceptor=""></plugin>
23     </plugins>
24     <!-- 环境:配置mybatis的环境 -->
25     <environments default="">
26        <!-- 环境变量:可以配置多个环境变量,比如使用多数据源时,就需要配置多个环境变量 -->
27        <environment id="">
28           <!-- 事务管理器 -->
29           <transactionManager type=""></transactionManager>
30           <!-- 数据源 -->
31           <dataSource type=""></dataSource>
32        </environment> 
33     </environments>
34     <!-- 数据库厂商标识 -->
35     <databaseIdProvider type=""></databaseIdProvider>
36     <!-- 映射器:指定映射文件或者映射类 -->
37     <mappers></mappers>
38 </configuration>
View Code
复制代码

 

4、mybatis映射

它分为两部分映射:sql语句映射和查询结果的映射。

1
2
3
4
<insert id="insertUser" parameterType="User">
  insert into users (id, username, password)
  values (#{id}, #{username}, #{password})
</insert>

   User 类型的参数对象传递到了语句中,会查找 id、username 和 password 属性,然后将它们的值传入预处理语句的参数中。

1
2
3
4
5
<select id="selectUsers" resultType="com.someapp.model.User">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

  这样的一个 JavaBean 可以被映射到 ResultSet,就像映射到 HashMap 一样简单。

 

5、MyBatis中实现SQL映射的常见标签

select、insert、update 和delete标签

select标签用来映射查询语句,它是MyBatis中最常用的标签之一。select标签的使用非常简单的。例如: 

1
2
3
<select id="selectUser" parameterType="int" resultType="hashmap">
SELECT * FROM TB_USER WHERE ID = #{id}
</select>

  这个语句被称作selectUser,其接受一个int (或Integer) 类型的参数,并返回一个HashMap类型的对象,HashMap中的键是列名,值便是结果行中的对应值。

注意:参数符号#{id},这是告诉MyBatis创建一个预处理语句参数。通过JDBC,这样的一个参数在SQL中会由一个“?”来标识,并被传递到一个新的预处理语句中。以上MyBatis配置文件执行时会生成如下JDBC 代码:

1
2
3
string selectUser = "SELECT * FRON TB_USER WHERE ID=?";
Preparedstatement ps = conn.prepareStatement(selectUser) ;
ps.setInt(1,id);

  

#{}和${}的区别是什么?

(1)mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值。

(2)mybatis在处理${}时,就是把${}替换成变量的值。

一级缓存和二级缓存的区别是什么?

(1)但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。

在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

(2)二级缓存也称为全局缓存,它指的是多个 SqlSession 共享的缓存,位于 SqlSessionFactory 内部,具有相对较长的生命周期。

当从一级缓存中未找到数据时,MyBatis 会尝试从二级缓存中查找数据,并将查询结果存储到二级缓存中,供后续的 SqlSession 使用。

 

6、动态SQL

在实际项目开发中,经常需要根据不同条件拼接SQL语句,拼接时还要确保不能忘了必要的空格,有时候还要注意省掉列名列表最后的逗号...等等。在使用JDBC 或其他类似持久层框架操作数据库时,处理这种情况是非常麻烦的,甚至可以用痛苦来形容,而在MyBatis中利用动态SQL这一特性可以很简单地解决这个问题。

常用的动态SQL元素包括:

  • if
  • choose (when、otherwise)
  • where
  • set
  • foreach
  • bind
1
2
3
4
5
6
7
8
9
<mapper namespace="cn.mybatis.mapper.EmployeeMapper">
  <select id="selectEmployeeByIdLike" resultTypem"cn.mybatis.domain.Employee">
    SELECT * FROM tb_employee WHERE state = 'ACTIVE'
    <!-- 可选条件,如果传进来的参数有id属性,则加上id查询条件-->
    <if test="id != null">
        and id = #{id}
    </if>
  </select>
</mapper>

  以上语句提供了一个可选的根据id查找Employee的功能。如果没有传入id,那么所有处于"ACTIVE"状态的Employee都会被返回。反之,若传入了id,那么就会把查找id内容的Employee结果返回。

1
2
3
public Interface EmployeeMapper {
    List<Employee> selectEmployeeByIdLike (HashMap<String,Object> params);
}

  以上代码提供了一个和EmployeeMapper.xml中的select元素的id同名的方法,需要注意的是,selectEmployeeByIdLike 接收一个 HashMap 作为参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static void main(string[] args) throws Exception
{
    // 读取mybatis-config.xml 文件
    Inputstream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    // 初始化mybatis,创建SqlSessionFactory 类的实例
    sqlsessionFactory sqlSessionEactory = new sqlsessionFactoryBullder().build(inputStream);
    // 创建Session实例
    sqlSesaion seasion = sqlsessionFactory.openSession();
    DynamicsQlTest t = new DynamicSQITest();
    t.testSelectEmployeeByIdLike(sesion);
    // 提交事务
    sesion.commit();
    // 关闭Session
    session.close();
}
 
// 测试<select id="selectEmployeeByIdLike"...>
public void testSelectemployeeByIdLike(Sqlsession session)
{
    // 获得EmployeeMapper接口的代理对象
    EmployeeMapper em = session.getMapper(EmployeeMapper.class);
    // 创建一个HashMap存储参数
    HashMap<String, Object> params = new HashMap<String, Object>();
    // 设置id属性
    params.put("id", 1);
    // 调用EmployeeMapper接口的selectEmployeeByIdLike方法
    List<Employee> list = em.selectEmployeeByIdLike(params);
    // 查看查询结果
    list.foEach(employee -> System.out.printIn(employee));
}

  运行上面的main方法,其通过SqlSession的getMapper(Class<T> type)方法获得mapper接口的代理对象EmployeeMapper。调用selctEmployeeByIdLike方法时会执行EmployeeMapper.xm中<select id="selctEmployeeByIdLike".../>元素中定义的sql语句。控制台显示如下:

DEBUG [main]==> Preparing: SELBCT * FRON tb_employee WHERE state = 'ACTIVE' and id= ?

DEBUG [main]==> Parameters:

DEBUG [main]<== Total:2

Employee [id=1,loginname=jack,password=123456,name=马云,sex=男,age=26,phone=13900000001,sal=9800.0,state=ACTIVE]