MyBatis的核心组件分为四个部分:
- SqlSessionFactoryBuilder(构造器):会根据配置或者代码来生成SqlSessionFactory,采用的是分步构建的Builder模式.
- SqlSessionFactory(工厂接口):用它来生成SqlSession,使用的是工厂模式.
- SqlSession(会话):一个既可以发送SQL执行返回结果,也可以获取Mapper的接口.一般我们会让其在业务逻辑代码中"消失".而使用的是MyBatis提供的SQL Mapper接口编程技术,它能提高代码的可读性和可维护性..
- SQL Mapper(映射器):由一个Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则.它负责发送SQL去执行,并返回结果.
SqlSessionFactory(工厂接口)
使用MyBatis首先是使用配置或者代码去生产SqlSessionFactory,而MyBatis提供了构造器SqlSessionFactoryBuilder(没有成员,只有一堆重载的builder方法,是类,只继承了Object),它提供了一个类Configuration作为引导,采用的是Builder模式.具体的分步则是在Configuration类里面完成的.
通过读取配置文件或者通过Java代码的形式去生成SqlSessionFactory.推荐使用XML形式,因为代码的形式在修改时会比较麻烦.当配置了XML或者提供代码后,MyBatis会读取配置文件,通过Configuration类对象构建整个MyBatis的上下文.SqlSessionFactory是一个接口,在MyBatis中它存在两个实现类:SqlSessionManager和DefaultSqlSessionFactory.一般而言是通过后者来实现的.而前者使用在多线程的环境中,它的具体实现依靠DefaultSqlSessionFactory.
每个基于MyBatis的应用都是以一个SqlSessionFactory的实例为中心的,而SqlSessionFactory唯一的作用就是生产MyBatis的核心接口对象SqlSession.所以他的责任是唯一的.我们往往会采用单例模式处理它.
MyBatis中的XML分为两类:
- 基础配置文件,通常只有一个,主要是配置一些最基本的上下文参数和运行环境;
- 映射文件,它可以配置映射关系,SQL,参数等信息.
基础配置文件中可以配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases><!--别名-->
<typeAlias alias="role" type="com.learn.ssm.chapter3.pojo.Role" />
</typeAliases>
<!--环境配置,连接的数据库,这里使用的是MySQL-->
<environments default="mysql">
<environment id="mysql">
<!--指定事务管理的类型,这里简单使用Java的JDBC的提交和回滚设置-->
<transactionManager type="JDBC"></transactionManager>
<!--dataSource 指连接源配置,POOLED是JDBC连接对象的数据源连接池的实现-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybbs"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</dataSource>
</environment>
</environments>
<mappers>
<!--这是告诉Mybatis去哪找持久化类的映射文件,对于在src下的文件直接写文件名,
如果在某包下,则要写明路径,如:com/mybatistest/config/User.xml-->
<mapper resource="User.xml"></mapper>
</mappers>
</configuration>
除非有特殊的需求,才会使用代码创建SqlSessionFactory,比如在配置文件中,需要配置加密过的数据库用户名和密码,需要我们在生成SqlSessionFactory前解密为明文的时候,才会考虑使用这种方式.
SqlSession
SqlSession是MyBatis的核心接口,它有两个实现类:
- DefaultSqlSession:单线程使用,
- SqlSessionManager:多线程使用
SqlSession类似于一个JDBC中的Connection对象,代表一个连接资源的启用.SqlSession的作用有3个:
- 获取Mapper接口.
- 发送SQL给数据库.
- 控制数据库事务.
SqlSession只是一个门面接口,真正干活的是Executor.
SqlSession获取Mapper接口和发送SQL的功能需要先实现映射器的功能.
SQL Mapper(映射器)
映射器是MyBatis中最重要,最复杂的组件,由一个接口和对应的XML文件(或注解)组成.
映射器可以配置以下内容:
- 描述映射规则.
- 提供SQL语句,并可以配置SQL参数类型,返回类型,缓存刷新等信息.
- 配置缓存.
- 提供动态SQL.
映射器的主要作用就是将SQL查询到的结果映射为一个POJO,或者将POJO的数据插入到数据库中,并定义一些关于缓存等的重要内容.MyBatis运用了动态代理技术为接口生成一个代理对象,代理对象会去处理相关的逻辑.
用XML方式创建映射器(推荐):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.RoleMapper">
<select id="getRole" parameterType="long" resultType="role">
SELECT id,role_name as roleName,note FROM role WHERE id =#{id}
</select>
</mapper>
MyBatis在默认情况下提供自动映射,只要SQL返回的列名能和POJO对应起来即可.
注解实现映射器:
这种方式只需要一个接口就可以通过注解来诸如SQL:
package com.mybatis.mapper;
import org.apache.ibatis.annotations.Select;
import com.mybatis.po.Role;
public interface RoleMapper2 {
@Select("select id,role_name as roleName,note from t_role where id=#{id}")
public Role getRole(Long id);
}
如果注解和XML同时定义时,XML将会覆盖掉注解方式,推荐使用的是XML方式定义映射器.
使用注解的方式,当SQL语句比较复杂时,会降低代码的可读性,不利于日后的维护和修改.
XML可以相互引入,而注解不可以.
两种发送SQL的方式:
- 用SqlSession发送SQL
- 用Mapper接口发送SQL
推荐使用Mapper接口的方式,理由有:
- 使用Mapper接口编程可以消除SqlSession带来的功能性代码,提高可读性.
- 使用Mapper接口的方式,IDE会提示错误和校验,而使用SqlSession的方式只有在运行中才能知道是否会产生错误.
生命周期
根据每一个组件的作用去确定其生命周期
SqlSessionFactoryBuilder的作用在于创建SqlSessionFactory,创建成功后,就失去了作用,所以它只能存在于创建SqlSessionFactory的方法中,而不要让其长期存在.
SqlSessionFactory可以被认为是一个数据库连接池,它的作用是创建SqlSession接口对象.因为MyBatis的本质就是Java对数据库的操作,所以SqlSessionFactory的生命周期存在于整个MyBatis的应用中.所以一旦创建了SqlSessionFactory,就要长期保存他,直至不再使用MyBatis引用.
- 如果存在多个数据库连接池会导致数据库连接资源被消耗光,出现系统宕机等情况,所以一般希望SqlSessionFactory作为一个单例,在应用中被共享.
SqlSession相当于一个数据库连接对象,它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让他归还给SqlSessionFactory.
Mapper是一个接口,由SqlSession所创建,它的最大生命周期至多和SqlSession保持一致,应该小于等于SqlSession的生命周期.Mapper代表的是一个请求中的业务处理,所以它应该在一个请求中,一旦处理完了相关的业务,就应该废弃它.
MyBatis执行流程:
创建一个SqlSessionFactoryBuilder对象,调用它的duilder方法
- 该方法会创建XMLConfigBuilder对象读取并解析MyBatis的全局配置文件,,将配置信息封装为Environment对象存储到Configuration对象中,根据配置信息创建SqlSessionFactory对象.
- XMLMapperBuilder读取并解析映射文件创建MappedStatement对象,将此对象存储在Configuration对象中.
- SqlSessionFactory是个接口,默认会使用DefaultSqlSessionFactory对象.
使用DefaultSqlSessionFactory对象的openSession方法
- 该方法会返回一个SqlSession,SqlSession是个接口,默认会返回DefaultSqlSession对象.
- 每个DefaultSqlSession中有一个Executor成员,Executor接口有四个实现类:
- 如果使用getMapper方法,会使用动态代理返回一个SqlSession对应的代理对象
Executor会使用StatementHandler来执行SQL语句,而SQL语句对应的是MappedStatement,因此还需将MappedStatement对象传给StatementHandler对象.
执行过程中需要使用ParameterHandler来获取参数,用TypeHandler来处理java数据类型和数据表数据类型之间的映射和转换.
而用ResultSetHandler来处理结果集,期间又会使用到TypeHandler来处理java数据类型和数据表数据类型之间的映射和转换.
以上就是MyBatis的基本执行流程.
MyBatis的一级缓存及二级缓存
MyBatis的一级缓存是SqlSession级缓存
- 每个SqlSession使用各自的缓存.
- 一级缓存不需要POJO对象可序列化
- 如果不进行commit,是不会有一级缓存的.
- 一级缓存默认使用PerpetualCache缓存.
MyBatis的二级缓存是SqlSessionFactory级缓存
- 二级缓存可在多个SqlSession之间共享缓存,因此缓存需要保证线程安全.
- 二级缓存要求POJO对象可序列化.
- 二级缓存默认使用SynchronizedCache缓存.
缓存基本执行流程:
执行SQL时首先到缓存中找,如果不存在,访问数据库执行SQL,将查询到的结果放入缓存并将结果返回,如果缓存中有,直接从缓存中取,不访问数据库.期间进行增删改操作会刷新缓存.