MyBatis
一、什么是MyBatis
1、简介
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对ibatis进行一些改进。
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
对jdbc的封装框架有哪些:Hibernate,dbutils,jdbcTemplate[spring],mybatis
原理:Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
每一个 MyBatis 的应 用程序 都以一 个 SqlSessionFactory 对象的 实例为 核心。 SqlSessionFactory 对 象 的 实 例 可 以 通 过 SqlSessionFactoryBuilder 对 象 来 获 得 。 SqlSessionFactoryBuilder 对象可以通过 XML 配置文件,或从以往使用惯例中准备好的 Configuration 类实例中来构建 SqlSessionFactory 对象。
2、入门——从XML中构建SQLSessionFactory
1、接口式编程
原生: Dao ====> DaoImpl
mybatis: Mapper ====> xxMapper.xml
2、SqlSession代表和数据库的一次会话;用完必须关闭;
3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。
4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。
(将接口和xml进行绑定)
EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class);
5、两个重要的配置文件:
mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
sql映射文件:保存了每一个sql语句的映射信息: 将sql抽取出来。
步骤:
* 1、根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象 有数据源一些运行环境信息
* 2、sql映射文件;配置了每一个sql,以及sql的封装规则等。
* 3、将sql映射文件注册在全局配置文件中
* 4、写代码:
* 1)、根据全局配置文件得到SqlSessionFactory;
* 2)、使用sqlSession工厂,获取到sqlSession对象使用他来执行增删改查
* 一个sqlSession就是代表和数据库的一次会话,用完关闭
* 3)、使用sql的唯一标志来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。
2.1 从 XML 文件中构建 SqlSessionFactory 的实例非常简单。这里建议你使用类路径下的资 源文件来配置,但是你可以使用任意的 Reader 实例,这个实例包括由文字形式的文件路径 或 URL 形式的文件路径 file://来创建。MyBatis 包含了一些工具类,称作为资源,这些工具 类包含一些方法,这些方法使得从类路径或其它位置加载资源文件更加简单。
1 //获取SqlSessionFactory
2 public SqlSessionFactory getSqlSessionFactory() throws IOException {
3 //读取配置文件
4 String resource = "mybatis-config.xml";
5 Reader reader = Resources.getResourceAsReader(resource);
6 return new SqlSessionFactoryBuilder().build(reader);
7 }
mybatis-config.xml:
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>
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.jdbcUrl}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/ant/mybatis/UserMapper.xml"/>
mappers>
configuration>
2.2 获取sqlSession对象,执行增删改查方法
public void daoSession() throws IOException {
//获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try{
//获取接口的实现类 对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//mybatis会给自动的创建一个代理对象,代理对象去执行增删改查 方法
User user = userMapper.findUserById(2);
System.out.println(userMapper.getClass());
System.out.println(user);
}finally {
sqlSession.close();
}
}
User实例
package com.ant.mybatis;
public class User {
private Integer id;
private String name;
private Integer age;
private String address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
UserMapper.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.ant.mybatis.dao.UserMapper">
<select id="findUserById" resultType="com.ant.mybatis.User">
select * from user where id = #{id}
select>
mapper>
dao层的接口类
1 package com.ant.mybatis.dao;
2
3 import com.ant.mybatis.User;
4
5 public interface UserMapper {
6 //根据id查询User
7 public User findUserById(Integer id);
8 }
2.3 结果:
二、全局配置文件(mybatis-config.xml) 详解
1、运行时行为设置
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
2、typeAliases别名处理器
<typeAliases>
<package name="com.atguigu.mybatis.bean"/>
typeAliases>
* 批量起别名的情况下,使用@Alias注解为某个类型指定新的别名
3、typeHandlers-类型处理器
无论是 MyBatis 在预处理语句(PreparedStatement)中 设置一个参数时,还是从结果集中取出一个值时, 都会 用类型处理器将获取的值以合适的方式转换成 Java 类型。
// MapperConfig.xml
<typeHandlers>
<typeHandler javaType="String" jdbcType="VARCHAR" handler="org.mybatis.example.ExampleTypeHandler"/>
typeHandlers>
4、日期类型的处理
日期和时间的处理,JDK1.8以前一直是个头疼的 问题。我们通常使用JSR310规范领导者Stephen Colebourne创建的Joda-Time来操作。1.8已经实 现全部的JSR310规范了。
日期时间处理上,我们可以使用MyBatis基于 JSR310(Date and Time API)编写的各种日期 时间类型处理器。
MyBatis3.4以前的版本需要我们手动注册这些处 理器,以后的版本都是自动注册的。
5、plugins插件
插件是MyBatis提供的一个非常强大的机制,我们 可以通过插件来修改MyBatis的一些核心行为。插 件通过动态代理机制,可以介入四大对象的任何 一个方法的执行。
• Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
• ParameterHandler (getParameterObject, setParameters)
• ResultSetHandler (handleResultSets, handleOutputParameters)
• StatementHandler (prepare, parameterize, batch, update, query)
6、environments-指定具体环境
id:指定当前环境的唯一标识
transactionManager、和dataSource都必须有
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
transactionManager
• type: JDBC | MANAGED | 自定义
– JDBC:使用了 JDBC 的提交和回滚设置,依赖于从数 据源得到的连接来管理事务范围。 JdbcTransactionFactory
– MANAGED:不提交或回滚一个连接、让容器来管理 事务的整个生命周期(比如 JEE 应用服务器的上下 文)。 ManagedTransactionFactory
– 自定义:实现TransactionFactory接口,type=全类名/ 别名
dataSource
• type: UNPOOLED | POOLED | JNDI | 自定义
– UNPOOLED:不使用连接池, UnpooledDataSourceFactory
– POOLED:使用连接池, PooledDataSourceFactory
– JNDI: 在EJB 或应用服务器这类容器中查找指定的数 据源
– 自定义:实现DataSourceFactory接口,定义数据源的 获取方式。
• 实际开发中我们使用Spring管理数据源,并进行 事务控制的配置来覆盖上述配置
7、environment-指定具体环境
transactionManager:
• type: JDBC | MANAGED | 自定义
– JDBC:使用了 JDBC 的提交和回滚设置,依赖于从数 据源得到的连接来管理事务范围。 JdbcTransactionFactory
– MANAGED:不提交或回滚一个连接、让容器来管理 事务的整个生命周期(比如 JEE 应用服务器的上下 文)。 ManagedTransactionFactory
– 自定义:实现TransactionFactory接口,type=全类名/ 别名
dataSource:
• type: UNPOOLED | POOLED | JNDI | 自定义
– UNPOOLED:不使用连接池, UnpooledDataSourceFactory
– POOLED:使用连接池, PooledDataSourceFactory
– JNDI: 在EJB 或应用服务器这类容器中查找指定的数 据源
– 自定义:实现DataSourceFactory接口,定义数据源的 获取方式。
• 实际开发中我们使用Spring管理数据源,并进行 事务控制的配置来覆盖上述配置
8、databaseIdProvider环境
MyBatis 可以根据不同的数据库厂商执行不同的语句。
• Type: DB_VENDOR
– 使用MyBatis提供的VendorDatabaseIdProvider解析数据库 厂商标识。也可以实现DatabaseIdProvider接口来自定义。
• Property-name:数据库厂商标识
• Property-value:为标识起一个别名,方便SQL语句使用 databaseId属性引用
• DB_VENDOR
– 会通过 DatabaseMetaData #getDatabaseProductName() 返回的字符 串进行设置。由于通常情况下这个字符串都非常长而且相同产品的不 同版本会返回不同的值,所以最好通过设置属性别名来使其变短
• MyBatis匹配规则如下:
– 1、如果没有配置databaseIdProvider标签,那么databaseId=null
– 2、如果配置了databaseIdProvider标签,使用标签配置的name去匹 配数据库信息,匹配上设置databaseId=配置指定的值,否则依旧为 null
– 3、如果databaseId不为null,他只会找到配置databaseId的sql语句
– 4、MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。
三、SQL映射配置文件(xxx-Mapper.xml)
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要定义 SQL 映射语句了。 但是,首先我们需要告诉 MyBatis 到哪里去找到这些语句。Java 在这方面没有提供一个很好 的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的 资源引用,或者字符表示,或 url 引用的完全限定名(包括 file:///URLs)。
1、mapper映射
mapper逐个注册SQL映射文件
// 使用相对于类路径的资源
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
mappers>
// 使用完全限定路径
<mappers>
<mapper url="file:///var/sqlmaps/AuthorMapper.xml"/>
<mapper url="file:///var/sqlmaps/BlogMapper.xml"/>
<mapper url="file:///var/sqlmaps/PostMapper.xml"/>
mappers>
或者使用批量注册: • 这种方式要求SQL映射文件名必须和接口名相同并且在同一目录下
2、MyBatis-映射文件
•cache –命名空间的二级缓存配置
•cache-ref – 其他命名空间缓存配置的引用。
•resultMap – 自定义结果集映射
•parameterMap – 已废弃!老式风格的参数映射
•sql –抽取可重用语句块。
•insert – 映射插入语句
•update – 映射更新语句
•delete – 映射删除语句
•select – 映射查询语句
3、insert、update、delete元素
数据修改语句 insert,update 和 delete 在它们的实现中非常相似:
<insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" useGeneratedKeys="" timeout="20000">
<update id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20000">
<delete id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20000">
4、主键生成方式
若数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),则可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上。
而对于不支持自增型主键的数据库(例如 Oracle),则可以使用 selectKey 子元素: selectKey 元素将会首先运行,id 会被设置,然 后插入语句会被调用
5、selectKey
6、参数(Parameters)传递
• 单个参数 – 可以接受基本类型,对象类型,集合类型的值。这种情况 MyBatis可直接使用这个参数,不需要经过任何处理。
• 多个参数 – 任意多个参数,都会被MyBatis重新包装成一个Map传入。 Map的key是param1,param2,0,1…,值就是参数的值。
• 命名参数 – 为参数使用@Param起一个名字,MyBatis就会将这些参数封 装进map中,key就是我们自己指定的名字
• POJO – 当这些参数属于我们业务POJO时,我们直接传递POJO
• Map – 我们也可以封装多个参数为map,直接传递
7、参数处理
a. 看源码,了解mybatis怎么处理参数:
总结:参数多时会封装map,为了不混乱,我们可以使用@Param来指定封装时使用的key; #{key}就可以取出map中的值; (@Param("id")Integer id,@Param("lastName")String lastName); ParamNameResolver解析参数封装map的; public Object getNamedParams(Object[] args) { final int paramCount = names.size(); //1、参数为null直接返回 if (args == null || paramCount == 0) { return null; //2、如果只有一个元素,并且没有Param注解;args[0]:单个参数直接返回 } else if (!hasParamAnnotation && paramCount == 1) { return args[names.firstKey()]; //3、多个元素或者有Param标注 } else { final Mapparam = new ParamMap
b. 参数也可以指定一个特殊的数据类型:
#{property,javaType=int,jdbcType=NUMERIC}
像 MyBatis 的剩余部分,javaType 通常可以从参数对象中来确定,除非对象是一个 HashMap。那么 javaType 应该被确定来保证使用正确类型处理器。
对于数值类型,对于决定有多少数字是相关的,有一个数值范围。 #{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
– javaType 通常可以从参数对象中来去确定:
– 如果 null 被当作值来传递,对于所有可能为空的列, jdbcType 需要被设置
– 对于数值类型,还可以设置小数点后保留的位数:
– mode 属性允许指定 IN,OUT 或 INOUT 参数。如果参数 为 OUT 或 INOUT,参数对象属性的真实值将会被改变, 就像在获取输出参数时所期望的那样。
参数位置支持的属性 – javaType、jdbcType、mode、numericScale、 resultMap、typeHandler、jdbcTypeName、expression
• 实际上通常被设置的是: 可能为空的列名指定 jdbcType
• #{}:可以获取map中的值或者pojo对象属性的值;
• ${}:可以获取map中的值或者pojo对象属性的值;
区别:
select * from tbl_employee where id=${id} and last_name=#{lastName}
Preparing: select * from tbl_employee where id=2 and last_name=?
#{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
${}:取出的值直接拼装在sql语句中;会有安全问题;
大多情况下,我们去参数的值都应该去使用#{};
eg:
原生jdbc不支持占位符的地方我们就可以使用${}进行取值
比如分表、排序。。。;按照年份分表拆分
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} ${order}
8、 select元素
• Select元素来定义查询操作。
• Id:唯一标识符。 – 用来引用这条语句,需要和接口的方法名一致
• parameterType:参数类型。 – 可以不传,MyBatis会根据TypeHandler自动推断
• resultType:返回值类型。 – 别名或者全类名,如果返回的是集合,定义集合中元 素的类型。不能和resultMap同时使用
select 元素有很多属性允许你配置,来决定每条语句的作用细节。
<select id=”selectPerson” parameterType=”int”
parameterMap=”deprecated” resultType=”hashmap”
resultMap=”personResultMap” flushCache=”false”
useCache=”true” timeout=”10000” fetchSize=”256”
statementType=”PREPARED” resultSetType=”FORWARD_ONLY” >
a. 查询 返回List集合
mapper.xml
b. 查询返回Map
返回一条记录的map:
resultType直接可以写map,以为mybatis已经为jdk起了别名。
多条记录封装一个map:
//多条记录封装一个map:Map:键是这条记录的主键,值是记录封装后的javaBean //@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key @MapKey("lastName") public MapgetEmpByLastNameLikeReturnMap(String lastName);
<select id="getEmpByLastNameLikeReturnMap" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where last_name like #{lastName} select>
Mapmap = mapper.getEmpByLastNameLikeReturnMap("%r%"); System.out.println(map);
9、自动映射
• 1、全局setting设置
– autoMappingBehavior默认是PARTIAL,开启自动映射 的功能。唯一的要求是列名和javaBean属性名一致
– 如果autoMappingBehavior设置为null则会取消自动映射
– 数据库字段命名规范,POJO属性符合驼峰命名法,如 A_COLUMNaColumn,我们可以开启自动驼峰命名规 则映射功能,mapUnderscoreToCamelCase=true。
• 2、自定义resultMap,实现高级结果集映射。
10、resultMap
• constructor - 类在实例化时, 用来注入结果到构造方法中
– idArg - ID 参数; 标记结果作为 ID 可以帮助提高整体效能
– arg - 注入到构造方法的一个普通结果
• id – 一个 ID 结果; 标记结果作为 ID 可以帮助提高整体效能
• result – 注入到字段或 JavaBean 属性的普通结果
• association
– 一个复杂的类型关联;许多结果将包成这种类型
– 嵌入结果映射 – 结果映射自身的关联,或者参考一个
• collection
– 复杂类型的集 – 嵌入结果映射 – 结果映射自身的集,或者参考一个
• discriminator
– 使用结果值来决定使用哪个结果映射
– case – 基于某些值的结果映射
• 嵌入结果映射 – 这种情形结果也映射它本身,因此可以包含很多相同的元 素,或者它可以参照一个外部的结果映射。
自定义结果集映射规则:
关联查询-级联熟悉封装操作:
11、id & result
• id 和 result 映射一个单独列的值到简单数据类型 (字符串,整型,双精度浮点数,日期等)的属性或字段。
12、association
• 复杂对象映射
• POJO中的属性可能会是一个对象
• 我们可以使用联合查询,并以级联属性的方式封 装对象。
• 使用association标签定义对象的封装规则
• association-嵌套结果集
• association-分段查询
select:调用目标的方法查询当前属性的值
column:将指定列的值传入目标方法
• association-分段查询&延迟加载
• 开启延迟加载和属性按需加载
在使用,调用到的时候 才去进行加载。
13、Collection-集合类型&嵌套结果集
collection:定义关联集合类型的属性的封装规则
ofType:指定集合里面元素的类型
Collection-分步查询&延迟加载
14、分步查询传递多列值 和 fetchType
扩展:多列的值传递过去:
将多列的值封装map传递;
column="{key1=column1,key2=column2}"
fetchType="lazy":表示使用延迟加载;
- lazy:延迟
- eager:立即
eg:
<collection property="emps" select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId" column="{deptId=id}" fetchType="lazy">collection>
15、discriminator鉴别器
鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为
封装Employee:
如果查出的是女生:就把部门信息查询出来,否则不查询;
如果是男生,把last_name这一列的值赋值给email;
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <discriminator javaType="string" column="gender"> <case value="0" resultType="com.atguigu.mybatis.bean.Employee"> <association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> association> case> <case value="1" resultType="com.atguigu.mybatis.bean.Employee"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="last_name" property="email"/> <result column="gender" property="gender"/> case> discriminator> resultMap>
四、MyBatis-动态SQL
• 动态 SQL是MyBatis强大特性之一。极大的简化我们拼装 SQL的操作。
• 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处 理器相似。
• MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作。
– if – choose (when, otherwise) – trim (where, set) – foreach
1、if
2、choose (when, otherwise)
3、trim (where, set)
在使用
where
set
* 后面多出的and或者or where标签不能解决
prefix="":前缀:trim标签体中是整个字符串拼串 后的结果。
prefix给拼串后的整个字符串加一个前缀
prefixOverrides="":
前缀覆盖: 去掉整个字符串前面多余的字符
suffix="":后缀
suffix给拼串后的整个字符串加一个后缀
suffixOverrides=""
后缀覆盖:去掉整个字符串后面多余的字符
trim
4、foreach
• 动态 SQL 的另外一个常用的必要操作是需要对一个集合 进行遍历,通常是在构建 IN 条件语句的时候。
• 当迭代列表、集合等可迭代对象或者数组时 – index是当前迭代的次数,item的值是本次迭代获取的元素
• 当使用字典(或者Map.Entry对象的集合)时 – index是键,item是值
* foreach批量插入
5、bind
• bind 元素可以从 OGNL 表达式中创建一个变量并 将其绑定到上下文。比如:
五、MyBatis-缓存机制
• MyBatis 包含一个非常强大的查询缓存特性,它可以非 常方便地配置和定制。缓存可以极大的提升查询效率。
• MyBatis系统中默认定义了两级缓存。
• 一级缓存和二级缓存。
– 1、默认情况下,只有一级缓存(SqlSession级别的缓存, 也称为本地缓存)开启。
– 2、二级缓存需要手动开启和配置,他是基于namespace级 别的缓存。
– 3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们 可以通过实现Cache接口来自定义二级缓存
1、一级缓存
• 一级缓存(local cache), 即本地缓存, 作用域默认 为sqlSession。当 Session flush 或 close 后, 该 Session 中的所有 Cache 将被清空。
• 本地缓存不能被关闭, 但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域. • 在mybatis3.1之后, 可以配置本地缓存的作用域. 在 mybatis.xml 中配置
* 一级缓存:(本地缓存):sqlSession级别的缓存。一级缓存是一直开启的;SqlSession级别的一个Map
* 与数据库同一次会话期间查询到的数据会放在本地缓存中。
* 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库;
* 一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是,还需要再向数据库发出查询):
* 1、sqlSession不同。
* 2、sqlSession相同,查询条件不同.(当前一级缓存中还没有这个数据)
* 3、sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
* 4、sqlSession相同,手动清除了一级缓存(缓存清空)
2、二级缓存
• 二级缓存(second level cache),全局作用域缓存
• 二级缓存默认不开启,需要手动配置
• MyBatis提供二级缓存的接口以及实现,缓存实现要求 POJO实现Serializable接口
• 二级缓存在 SqlSession 关闭或提交之后才会生效
二级缓存:(全局缓存):基于namespace级别的缓存:一个namespace对应一个二级缓存: * 工作机制:
* 1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
* 2、如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;
* 3、sqlSession===EmployeeMapper==>Employee
* DepartmentMapper===>Department
* 不同namespace查出的数据会放在自己对应的缓存中(map)
* 效果:数据会从二级缓存中获取
* 查出的数据都会被默认先放在一级缓存中。
* 只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
* 使用:
* 1)、开启全局二级缓存配置:
* 2)、去mapper.xml中配置使用二级缓存:
* 3)、我们的POJO需要实现序列化接口
3、缓存相关属性
• eviction=“FIFO”:缓存回收策略:
• LRU – 最近最少使用的:移除最长时间不被使用的对象。
• FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
• SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
• WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
• 默认的是 LRU。
• flushInterval:刷新间隔,单位毫秒 • 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
• size:引用数目,正整数 • 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
• readOnly:只读,true/false
• true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象 不能被修改。这提供了很重要的性能优势。
• false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些, 但是安全,因此默认是false。
4、缓存有关设置
• 1、全局setting的cacheEnable: – 配置二级缓存的开关。一级缓存一直是打开的。cacheEnabled=true:false:关闭缓存(二级缓存关闭)(一级缓存一直可用的)
• 2、select标签的useCache属性: – 配置这个select是否使用二级缓存。一级缓存一直是使用的
• 3、sql标签的flushCache属性: – 增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。 查询默认flushCache=false。
• 4、sqlSession.clearCache(): – 只是用来清除一级缓存。
• 5、当在某一个作用域 (一级缓存Session/二级缓存 Namespaces) 进行了 C/U/D 操作后,默认该作用域下所 有 select 中的缓存将被clear。
5、第三方缓存整合
• EhCache 是一个纯Java的进程内缓存框架,具有快速、精 干等特点,是Hibernate中默认的CacheProvider。
• MyBatis定义了Cache接口方便我们进行自定义扩展。
• 步骤:
– 1、导入ehcache包,以及整合包,日志包 ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar
– 2、编写ehcache.xml配置文件
xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore path="D:\44\ehcache" /> <defaultCache maxElementsInMemory="10000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> defaultCache> ehcache>
– 3、配置cache标签 –
• 参照缓存:若想在命名空间中共享相同的缓存配置和实例。 可以使用 cache-ref 元素来引用另外一个缓存。
六、MyBatis-Spring整合