- MyBatis 是支持定制化 SQL、存储过程以及高级
映射的优秀的持久层框架。 - MyBatis 避免了几乎所有的 JDBC 代码和手动设
置参数以及获取结果集。 - MyBatis可以使用简单的XML或注解用于配置和原
始映射,将接口和Java的POJO(Plain Old Java
Objects,普通的Java对象)映射成数据库中的记
录。 - 原是Apache的一个开源项目iBatis, 2010年6月这
个项目由Apache Software Foundation 迁移到了
Google Code,随着开发团队转投Google Code
旗下, iBatis3.x正式更名为MyBatis ,代码于
2013年11月迁移到Github(下载地址见后)。 - iBatis一词来源于“internet”和“abatis”的组合,是
一个基于Java的持久层框架。 iBatis提供的持久
层框架包括SQL Maps和Data Access Objects
(DAO)。
- MyBatis是一个半自动化的持久化层框架。
- JDBC
– a. SQL夹在Java代码块里,耦合度高导致硬编码内伤。
– b. 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见。 - Hibernate和JPA
– a. 长难复杂SQL,对于Hibernate而言处理也不容易。
– b. 内部自动生产的SQL,不容易做特殊优化。
– c. 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难。
导致数据库性能下降。 - 对开发人员而言,核心sql还是需要自己优化。
- sql和java编码分开,功能边界清晰,一个专注业务、
一个专注数据。
https://mybatis.org/mybatis-3/zh/index.html
创建表名为tbl_employee
CREATE TABLE `tbl_employee` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `last_name` VARCHAr(255) COLLATE utf8_german2_ci DEFAULT NULL, `gender` VARCHAr(10) COLLATE utf8_german2_ci DEFAULT NULL, `email` VARCHAr(255) COLLATE utf8_german2_ci DEFAULT NULL, PRIMARY KEY (`id`) )2.2.创建对应的javaBean
创建在com.tedu.java.pojo目录下
![在
package com.tedu.pojo;
public class Employee {
private Integer id;
private String lastName;
private String email;
private String gender;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Employee [id=" + id + ", lastName=" + lastName + ", email="
+ email + ", gender=" + gender + "]";
}
}
2.3.创建mybatis配置文件,sql映射文件
a. 创建全局配置文件
b. 创建sql映射文件
select id,last_name lastName,email,gender from tbl_employee where id = #{id}
c.创建dao接口
package com.tedu.dao;
import com.tedu.pojo.Employee;
public interface EmployeeMapper {
public Employee getEmployeeById(Integer id);
}
三、MyBatis-全局配置文件
- 1、创建MyBatis全局配置文件
– MyBatis 的全局配置文件包含了影响 MyBatis 行为甚深
的设置(settings)和属性(properties)信息、如数据
库连接池信息等。指导着MyBatis进行工作。我们可以
参照官方文件的配置示例。 - 2、创建SQL映射文件
– 映射文件的作用就相当于是定义Dao接口的实现类如何
工作。这也是我们使用MyBatis时编写的最多的文件。 - 3、测试
package com.tedu.test;
import com.tedu.dao.EmployeeMapper;
import com.tedu.pojo.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisTest {
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
return new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void test2() throws IOException {
//1.获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2.获取sqlSession对象
SqlSession openSession = sqlSessionFactory.openSession();
//3.取货接口的实现类
try {
//会为接口自动创建一个代理对象
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmployeeById(1);
System.out.println(employee);
} finally {
//资源的关闭
openSession.close();
}
}
}
注:
- SqlSession 的实例不是线程安全的,因此是不能
被共享的。 - SqlSession每次使用完成后需要正确关闭,这个
关闭操作是必须的。 - SqlSession可以直接调用方法的id进行数据库操
作,但是我们一般还是推荐使用SqlSession获取
到Dao接口的代理类,执行代理对象的方法,可
以更安全的进行类型检查操作。
MyBatis 的配置文件包含了影响 MyBatis 行为甚深的设置(settings)和属性(properties)信息。文档的顶层结构如下:
configuration 配置:
• properties 属性
• settings 设置
• typeAliases 类型命名
• typeHandlers 类型处理器
• objectFactory 对象工厂
• plugins 插件
• environments 环境
• environment 环境变量
• transactionManager 事务管理器
• dataSource 数据源
• databaseIdProvider 数据库厂商标识
• mappers 映射器
mybatis可以使用properties来引入外部properties配置文件的内容:
resource,引入类路径下的资源
url 引入网络中的资源
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=root
注:
- 如果属性在不只一个地方进行了配置,那么 MyBatis 将按
照下面的顺序来加载:
– 在 properties 元素体内指定的属性首先被读取。
– 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根
据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
– 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
| 设置参数 | 描述 | 有效值 | 默认值 |
|---|---|---|---|
| cacheEnabled | 该配置影响着所有的映射器中配置的缓存的全局开关 | true false | true |
| lazyLoadingEnabled | 延迟加载的全局开关,当开启时,所有关联的对象都会延迟加载。特定关联关系中可以通过设置fetchType属性来覆盖该项的开关状态 | true false | false |
| useColumnLabel | 使用列标签来代替列名。不同的驱动会有不同的变现 | true false | true |
| defaultStatementTimeOut | 设置超时时间,它决定驱动等待数据库响应的秒数 | Any positive integer | not set null |
| mapUnderScoreToCamelCase | 是否自动开启驼峰命名规则映射,即从经典的数据库列名到java类列属性的映射 | true false | false |
3.5.typeAliases别名处理器
- 类型别名是为 Java 类型设置一个短的名字,可以方便我们
引用某个类。
- 类很多的情况下,可以批量设置别名这个包下的每一个类
创建一个默认的别名,就是简单类名小写。
- 也可以使用@Alias注解为其指定一个别名
@Alias("Emp")
public class Employee {
}
注:值得注意的是,MyBatis已经为许多常见的 Java 类型内建
了相应的类型别名。它们都是大小写不敏感的,我们在起
别名的时候千万不要占用已有的别名。
| 别名 | 映射的类型 | 别名 | 映射的类型 | 别名 | 映射的类型 |
|---|---|---|---|---|---|
| _byte | byte | string | String | date | Date |
| _long | long | byte | Byte | decimal | BigDecimal |
| _short | short | long | Long | bigdecimal | BigDecimal |
| _int | int | short | Short | object | Object |
| _integer | integer | int | Integer | map | Map |
| _double | double | integer | Integer | hashmap | HashMap |
| _float | float | double | Double | list | List |
| _boolean | boolean | float | Float | arraylist | ArrayList |
| boolean | Boolean | collection | Collection | iterator | Iterator |
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型 。
| 类型处理器 | Java 类型 | JDBC 类型 |
|---|---|---|
| BooleanTypeHandler | java.lang.Boolean, boolean | 数据库兼容的BOOLEAN |
| ByteTypeHandler | java.lang.Byte, byte | 数据库兼容的NUMERIC 或BYTE |
| ShortTypeHandler | java.lang.Short, short | 数据库兼容的NUMERIC 或SHORT INTEGER |
| IntegerTypeHandler | java.lang.Integer, int | 数据库兼容的NUMERIC 或INTEGER |
| LongTypeHandler | java.lang.Long, long | 数据库兼容的NUMERIC 或LONG INTEGER |
| FloatTypeHandler | java.lang.Float, float | 数据库兼容的NUMERIC 或FLOAT |
| DoubleTypeHandler | java.lang.Double, double | 数据库兼容的NUMERIC 或DOUBLE |
| BigDecimalTypeHandler | java.math.BigDecimal | 数据库兼容的NUMERIC 或DECIMAL |
| StringTypeHandler | java.lang.String | CHAR, VARCHAR |
- 日期和时间的处理,JDK1.8以前一直是个头疼的
问题。我们通常使用JSR310规范领导者Stephen
Colebourne创建的Joda-Time来操作。1.8已经实
现全部的JSR310规范了。 - 日期时间处理上,我们可以使用MyBatis基于
JSR310(Date and Time API)编写的各种日期
时间类型处理器。 - MyBatis3.4以前的版本需要我们手动注册这些处
理器,以后的版本都是自动注册的。
- 我们可以重写类型处理器或创建自己的类型处理
器来处理不支持的或非标准的类型。 - 步骤:
- 实现org.apache.ibatis.type.TypeHandler接口或
者继承org.apache.ibatis.type.baseTypeHandler。 - 指定其映射某个JDBC类型(可选操作)。
- 在mybatis全局配置文件中注册。
- 实现org.apache.ibatis.type.TypeHandler接口或
- MyBatis可以配置多种环境,比如开发、测试和生
产环境需要有不同的配置。 - 每种环境使用一个environment标签进行配置并指
定唯一标识符。 - 可以通过environments标签中的default属性指定
一个环境的标识符来快速的切换环境。 - environment-指定具体环境:
- id:指定当前环境的唯一标识
- transactionManager、和dataSource都必须有
3.9.1.transactionManager
- type: JDBC | MANAGED | 自定义
- JDBC:使用了 JDBC 的提交和回滚设置,依赖于从数
据源得到的连接来管理事务范围。
JdbcTransactionFactory - MANAGED:不提交或回滚一个连接、让容器来管理
事务的整个生命周期(比如 JEE 应用服务器的上下
文)。 ManagedTransactionFactory - 自定义:实现TransactionFactory接口,type=全类名/
别名
- JDBC:使用了 JDBC 的提交和回滚设置,依赖于从数
- type: UNPOOLED | POOLED | JNDI | 自定义
- UNPOOLED:不使用连接池,UnpooledDataSourceFactory
- POOLED:使用连接池, PooledDataSourceFactory
- JNDI: 在EJB 或应用服务器这类容器中查找指定的数
据源
- 自定义:实现DataSourceFactory接口,定义数据源的
获取方式。 - 实际开发中我们使用Spring管理数据源,并进行
事务控制的配置来覆盖上述配置。
- MyBatis 可以根据不同的数据库厂商执行不同的语句。
- Type: DB_VENDOR - 使用MyBatis提供的VendorDatabaseIdProvider解析数据库厂商标识。也可以实现DatabaseIdProvider接口来自定义。 - Property-name:数据库厂商标识 - Property-value:为标识起一个别名,方便SQL语句使用databaseId属性引用
- MyBatis匹配规则如下:
- 如果没有配置databaseIdProvider标签,那么databaseId=null
- 如果配置了databaseIdProvider标签,使用标签配置的name去匹配数据库信息,匹配上设置databaseId=配置指定的值,否则依旧为null
- 如果databaseId不为null,他只会找到配置databaseId的sql语句
- MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库databaseId 属性的所有语句。如果同时找到带有 databaseId 和不带databaseId 的相同语句,则后者会被舍弃。
- mapper逐个注册SQL映射文件
package com.tedu.dao;
import com.tedu.pojo.Employee;
import org.apache.ibatis.annotations.Select;
public interface EmployeeMapperAnnotation {
@Select("select * from tbl_employee where id=#{id}")
public Employee getEmployeeById(Integer id);
}
- 或者使用批量注册:
这种方式要求SQL映射文件名必须和接口名相同并且在同一目录下:
四、MyBatis-映射文件
映射文件指导着MyBatis如何进行数据库增删改查,有着非常重要的意义;
- cache –命名空间的二级缓存配置。
- cache-ref – 其他命名空间缓存配置的引用。
- resultMap – 自定义结果集映射。
- parameterMap – 已废弃!老式风格的参数映射。
- sql –抽取可重用语句块。
- insert – 映射插入语句。
- update – 映射更新语句。
- delete – 映射删除语句。
- select – 映射查询语句。
| 属性名 | 注释 |
|---|---|
| id | 命名空间的唯一标识符 |
| parameterType | 将要传入语句的参数完全限定类名或者别名。这个属性是可选的,因为Mybatis可以通过TypeHandler推断出具体传入语句的参数类型,默认值为unset。 |
| flushCache | 将其设置为true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应插入、更新和删除语句)。 |
| timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为unset(依赖驱动) |
| statementType | STATEMENT,PREPARED或CALLABLE的一个。这会让MyBatis分别使用Statement,PreparedStatement |
| useGeneratedKeys | (仅对insert和update有效)这会对Mybatis 使用JDBC的getGeneratedKeys方法来获取出主键(比如:像MySQL和SQL Server这样的关系型数据库管理系统的自动递增字段),默认值:false |
| keyProperty | (仅对insert和update有效)唯一标记一个属性,Mybatis会通过getGeneratedKeys的返回值或者通过insert语句的selectKey子元素设置它的键值,默认值:unset |
| keyColumn | (仅对insert和update有效)通过生成的键值设置表中的列名,这个设置仅在默写数据库(像PostgreSQL是必须的,)当主键不是表中的第一列的时候需要设置,如果需要得到多个生成的列,也可以是逗号分割的属性名称列表。 |
| databaseId | 如果配置了databaseIdProvider,Mybatis会加载所有的不带databaseId或者匹配当前databaseId的语句;如果带或者不带的语句都有,这不带的会忽略。 |
a.若数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),则可以设置
useGeneratedKeys=”true”,然后再把keyProperty 设置到目标属性上。
insert into tbl_employee (last_name,email,gender) values (#{lastName},#{email},#{gender})
b.而对于不支持自增型主键的数据库(例如Oracle),则可以使用 selectKey 子元素:
selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用。
4.3.selectKeyselect crm_seq.nextval from dual insert into tbl_employee (last_name,email,gender) values (#{lastName},#{email},#{gender})
| keyProperty | selectKey语句结果应该被设置的目标属性 |
|---|---|
| keyColumn | 匹配属性的放回结果集中的列名称 |
| resultType | 结果的类型。Mybatis通常可以推算出来,但是为了更加确定写上也不会出现什么问题。Mybatis允许人呢和简单类型用作左肩的的类型,包括字符串。 |
| order | 可以设置为BEFORE或者AFTER。如果设置为BEFORE,那么它会先选择主键,设置keyProperty,然后执行插入语句。如果设置为AFTER,那么先执行插入语句,然后是selectKey元素。 |
| statementType | 与前面相同,Mybaits支持STATEMENT,PREPARED和CALLABLE语句的映射类型,分别代表PreparedStatement和CallableStatement类型。 |
- 单个参数
– 可以接受基本类型,对象类型,集合类型的值。这种情况MyBatis可直接使用这个参数,不需要经过任何处理。
public Employee getEmployeeById(Integer id);
- 多个参数
– 任意多个参数,都会被MyBatis重新包装成一个Map传入。Map的key是param1,param2,0,1…,值就是参数的值。
public Employee getEmpByIdAndLastName(@Param("id") Integer id,@Param("lastName") String lastName);
- 命名参数
– 为参数使用@Param起一个名字,MyBatis就会将这些参数封装进map中,key就是我们自己指定的名字。
public Employee getEmpByIdAndLastName(@Param("id") Integer id,@Param("lastName") String lastName);
- POJO
– 当这些参数属于我们业务POJO时,我们直接传递POJO。
public Long addEmployee(Employee employee);insert into tbl_employee (last_name,email,gender) values (#{lastName},#{email},#{gender})
- Map
– 我们也可以封装多个参数为map,直接传递。
public Employee getEmpByMap(Map4.5.select元素map);
-
Select元素来定义查询操作。
-
Id:唯一标识符。
– 用来引用这条语句,需要和接口的方法名一致。 -
parameterType:参数类型。
– 可以不传,MyBatis会根据TypeHandler自动推断。 -
resultType:返回值类型。
– 别名或者全类名,如果返回的是集合,定义集合中元
素的类型。不能和resultMap同时使用。
| 参数 | 解释 |
|---|---|
| pararmterType | 将会传入这条语句的参数类型的完全限定名或者别名。这个属性是可选的,因为Mybatis可以通过TypeHandler推断出具体传入的参数类型,默认值为unset。 |
| resultType | 从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合,那么应该是集合可以包含的类型,而不能是集合本身。改属性和resultMap不能同时使用。 |
| resultMap | 外部resultMap的命名引用。和resultType不能同时使用。 |
| flushCache | 将其设置为true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值为false。 |
| useCache | 将其设置为true,将会导致本条语句的结果被二级缓存,默认值对select元素为true。 |
| timeout | 这个设置是在抛出异常前,驱动程序等待数据库返回请求结果的秒数。默认值为unset(依赖驱动)。 |
| fetchSize | 影响驱动程序每次批量返回的结果行数。默认值为unset(依赖驱动)。 |
| statementType | STATEMENT,PREPARED或CALLABLE的一个。这会让Mybatis分别使用Statement,PreparedStatement或者CallableStatement,默认值:PREPARED。 |
| resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE或者SCROLL_INSENSITIVE中的一个,。 |
| dattabaseId | 如果配置了databaseIdProvider,Mybatis会加载所有不带databaseId或匹配当前databaseId的语句;如果带和不带的语句都有,则不带的会被忽略。 |
- 全局setting设置
– autoMappingBehavior默认是PARTIAL,开启自动映射
的功能。唯一的要求是列名和javaBean属性名一致。
– 如果autoMappingBehavior设置为null则会取消自动映射。
– 数据库字段命名规范,POJO属性符合驼峰命名法,如
A_COLUMNaColumn,我们可以开启自动驼峰命名规则映射功能,mapUnderscoreToCamelCase=true。 - 自定义resultMap,实现高级结果集映射。
- constructor
– 类在实例化时, 用来注入结果到构造方法中
– idArg - ID 参数; 标记结果作为 ID 可以帮助提高整体效能
– arg - 注入到构造方法的一个普通结果 - id
– 一个 ID 结果; 标记结果作为 ID 可以帮助提高整体效能 - result
– 注入到字段或 JavaBean 属性的普通结果 - association
– 一个复杂的类型关联;许多结果将包成这种类型
– 嵌入结果映射 – 结果映射自身的关联,或者参考一个 - collection
– 复杂类型的集
– 嵌入结果映射 – 结果映射自身的集,或者参考一个 - discriminator
– 使用结果值来决定使用哪个结果映射
– case
– 基于某些值的结果映射 - 嵌入结果映射
– 这种情形结果也映射它本身,因此可以包含很多相同的元
素,或者它可以参照一个外部的结果映射。
4.7.id&result
id 和 result 映射一个单独列的值到简单数据类型(字符串,整型,双精度浮点数,日期等)的属性或字段。
| 属性 | 解释 |
|---|---|
| property | 映射到列结果的字段或属性。例如:“username” 或者"address.street.number"。 |
| column | 数据表的列名。通常和resultSet.getString(columnName)的返回值一致。 |
| javaType | 一个Java类的完全限定名,或一个类型别名。如果映射到一个JavaBean,Mybatis通常可以判定类型。column |
| jdbcType | JDBC类型是紧紧需要对插入,更新和删除可能为空的列进行处理。 |
| typeHandler | 类型处理器。使用这个属性,可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。 |
• 复杂对象映射
• POJO中的属性可能会是一个对象
• 我们可以使用联合查询,并以级联属性的方式封
装对象。
• 使用association标签定义对象的封装规则。
association-分段查询
select:调用目标的方法查询当前属性的值
column:将指定列的值传入目标方法
association-分段查询&延迟加载:
开启延迟加载和属性按需加载
Collection-集合类型&嵌套结果集
select id="getEmpByIdStep" resultMap="MyEmployee">
select * from tbl_employee where id=#{id}
五、MyBatis-动态SQL
- 动态 SQL是MyBatis强大特性之一。极大的简化我们拼装
SQL的操作。 - 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处
理器相似。 - MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作。
– if
– choose (when, otherwise)
– trim (where, set)
– foreach
5.2.choose (when, otherwise)
5.3.trim (where, set)
where
select id="getEmpIf" resultType="com.tedu.java.bean.Employee">
select * from tbl_employee
id=#{id} and
last_name=#{lastName} and
email={email} and
gender=#{gender}
set
update tbl_employee last_name=#{lastName}, email=#{emial}, gender=#{gender} id=#{id}
trim
5.4.foreach动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。
六、MyBatis-缓存机制- MyBatis 包含一个非常强大的查询缓存特性,它可以非
常方便地配置和定制。缓存可以极大的提升查询效率。 - MyBatis系统中默认定义了两级缓存。
- 一级缓存和二级缓存。
– 1、默认情况下,只有一级缓存(SqlSession级别的缓存,
也称为本地缓存)开启。
– 2、二级缓存需要手动开启和配置,他是基于namespace级
别的缓存。
– 3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们
可以通过实现Cache接口来自定义二级缓存。
- 一级缓存(local cache), 即本地缓存, 作用域默认
为sqlSession。当 Session flush 或 close 后, 该
Session 中的所有 Cache 将被清空。 - 本地缓存不能被关闭, 但可以调用 clearCache()
来清空本地缓存, 或者改变缓存的作用域。 - 在mybatis3.1之后, 可以配置本地缓存的作用域.
在 mybatis.xml 中配置。
| localCacheScope | Mybatis利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。默认值为SESSION,这种情况下会缓存一个会话中执行的所有查询。如设置STATEMENT,本地会话仅用在语句执行上,对相同SqlSession的不同调用将不会共享数据 | SESSION/STETEMENT | SESSION |
|---|
一级缓存演示&失效情况
- 同一次会话期间只要查询过的数据都会保存在当
前SqlSession的一个Map中
–key:hashCode+查询的SqlId+编写的sql查询语句+参数。 - 一级缓存失效的四种情况
– 1、不同的SqlSession对应不同的一级缓存
– 2、同一个SqlSession但是查询条件不同
– 3、同一个SqlSession两次查询期间执行了任何一次增
删改操作
– 4、同一个SqlSession两次查询期间手动清空了缓存
- 二级缓存(second level cache),全局作用域缓存。
- 二级缓存默认不开启,需要手动配置。
- MyBatis提供二级缓存的接口以及实现,缓存实现要求POJO实现Serializable接口。
- 二级缓存在 SqlSession 关闭或提交之后才会生效。
- 使用步骤:
a.全局配置文件中开启二级缓存:。
b.需要使用二级缓存的映射文件处使用cache配置缓存
c.注意:POJO需要实现Serializable接口。
- eviction=“FIFO”:缓存回收策略:
a.LRU – 最近最少使用的:移除最长时间不被使用的对象。
b.FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
c.SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
d.WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
e.默认的是 LRU。 - flushInterval:刷新间隔,单位毫秒。
a.默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。 - size:引用数目,正整数。
a.代表缓存最多可以存储多少个对象,太大容易导致内存溢出。 - readOnly:只读,true/false。
a.true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
b.false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。
- 全局setting的cacheEnable:配置二级缓存的开关。一级缓存一直是打开的。
- select标签的useCache属性:配置这个select是否使用二级缓存。一级缓存一直是使用的。
- sql标签的flushCache属性:增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。查询默认flushCache=false。
- sqlSession.clearCache():只是用来清除一级缓存。
- 当在某一个作用域 (一级缓存Session/二级缓存Namespaces) 进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
- EhCache 是一个纯Java的进程内缓存框架,具有快速、精
干等特点,是Hibernate中默认的CacheProvider。 - MyBatis定义了Cache接口方便我们进行自定义扩展。
- 步骤:
a.导入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
b.编写ehcache.xml配置文件
- 配置cache标签:
@Test
public void testFirstLevelCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee empById = mapper.getEmpById(2);
System.out.println(empById);
SqlSessionFactory sqlSessionFactory1 = getSqlSessionFactory();
SqlSession openSession1 = sqlSessionFactory1.openSession();
EmployeeMapper mapper1 = openSession1.getMapper(EmployeeMapper.class);
Employee empById1 = mapper1.getEmpById(2);
System.out.println(empById1);
//true 没有创建新的对象
System.out.println(empById==empById1);
openSession.close();
}
@Test
public void testSecondLevelCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
SqlSession openSession1 = sqlSessionFactory.openSession();
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
EmployeeMapper mapper1 = openSession1.getMapper(EmployeeMapper.class);
Employee empById = mapper.getEmpById(2);
System.out.println(empById);
openSession.close();
//第二次查询出的数据是在二级缓存中拿到的
Employee empById1 = mapper1.getEmpById(2);
System.out.println(empById1);
openSession1.close();
}
}



