MyBatis
本文内容参考互联网,kuangstudy,感谢!!
概念
什么是mybatis
MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了[google code](baike.baidu.com/item/google code/2346604),并且改名为MyBatis。
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录
为什么需要mybatis
一个框架产生的缘由无非就是为了方便开发,减少代码量。
mybatis的优点
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件。易于学习,易于使用。通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射。
- 提供对象关系映射标签,支持对象关系组建维护。
- 提供xml标签,支持编写动态sql
入门
学习途径
- 官网:mybatis.org/mybatis-3/z…
- B站:通常来说对于一项技术的初级阶段,看视频还是非常有帮助的。
- 书籍:适合自律性强的人,比较乏味,但是通常书籍涉及的知识点非常全。
- 看博客:通常都是他人对一项技术的总结,能够了解到该技术的主要技术点,但是通常知识点不会覆盖的很全面,而且学习的思路也是别人整理后的思路,不利于形成自己的学习方式。
搭建环境
- 创建maven项目
- 创建数据库,并创建表student
CREATE TABLE `student` (
`id` varchar(30) DEFAULT NULL,
`name` varchar(30) DEFAULT NULL,
`age` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
添加依赖
依赖查询网站:mvnrepository.com/
<dependencies>
<!--mysql连接工具-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
</dependencies>
- 创建mybatis配置文件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>
<!--数据库链接配置-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--mysql驱动-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--mysql链接url-->
<property name="url" value="jdbc:mysql://10.36.2.65:6612/ta"/>
<!--mysql用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="talent"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="example.xml"/>
</mappers>
</configuration>
//在该文件中我们可以看到可以配置多个数据源,配置多个environment,但是生效的只能有一个。
- 创建mybatis工具类
public class MybatisUtils {
//创建SqlSessionFactory实例
public static SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
//获取SqlSession实例
public static SqlSession getSqlSession() throws IOException {
SqlSession sqlSession = MybatisUtils.getSqlSessionFactory().openSession();
return sqlSession;
}
}
- 创建bean
public class Student {
private String id;
private String name;
private int age;
public Student() {
}
public Student(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 创建mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.ExampleDao">
<select id="getOne" resultType="com.example.bean.Student">
select * from student limit 0,1
</select>
</mapper>
- 创建dao接口
public interface ExampleDao {
Student getOne();
}
- 测试
//有两种方式调用dao接口
public class ExampleDaoTest {
@Test
public void getOne() throws IOException {
SqlSession sqlSession = MybatisUtils.getSqlSession();
ExampleDao mapper = sqlSession.getMapper(ExampleDao.class);
Student one = mapper.getOne();
System.out.printf(one.toString());
}
@Test
public void getOne2() throws IOException {
SqlSession sqlSession = MybatisUtils.getSqlSession();
Student student = (Student)sqlSession.selectOne("com.example.dao.ExampleDao.getOne");
System.out.printf(student.toString());
}
}
sql和dao接口绑定
作用域和生命周期
我们知道最终执行sql操作的是SqlSession,而获取SqlSession实例需要通过SqlSessionFactory,SqlSessionFactory的创建需要通多SqlSessionFactoryBuilder。
public class MybatisUtils {
SqlSessionFactory sqlSessionFactory;
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
public static SqlSession getSqlSession() throws IOException {
MybatisUtils mybatisUtils = new MybatisUtils();
if (mybatisUtils.sqlSessionFactory == null){
mybatisUtils.getSqlSessionFactory();
}
SqlSession sqlSession = mybatisUtils.sqlSessionFactory.openSession();
return sqlSession;
}
}
通过代码可以看到
-
SqlSessionFactoryBuilder:主要是用来获取SqlSessionFactory实例的,所以一经创建SqlSessionFactory后就不在需要了,所以它的作用域也就是方法作用域。
-
SqlSessionFactory:使用来初始化SqlSession的,而在整个应用期间需要多次初始化SqlSession,所以SqlSessionFactory需要一直存在,所以最佳作用域是应用作用域
-
SqlSession:每个线程都应该有自己的SqlSession,因为不是线程安全的,所以每个请求完成后需要销毁。最佳的作用域是请求或方法作用域。
实现CRUD操作
select
- select是在项目开发中用到的最多的标签
- 在select标签中有很多属性
- id:命名空间中的唯一标识,同时也是用来绑定dao层接口的方法名
- parameterType:参数类型
- resultType:sql的返回值类型。
实例:根据id查询student表
-
在ExampleDao接口中添加接口
public interface ExampleDao { Student getOne(); Student getOneById(@Param("id")String id); }
-
在mapper.xml文件中添加sql
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.dao.ExampleDao"> <select id="getOne" resultType="com.example.bean.Student"> select * from student limit 0,1 </select> <select id="getOneById" resultType="com.example.bean.Student"> select * from student where id = "${id}" </select> </mapper>
-
写测试类测试
@Test public void getOneById() throws IOException { SqlSession sqlSession = MybatisUtils.getSqlSession(); ExampleDao mapper = sqlSession.getMapper(ExampleDao.class); Student one = mapper.getOneById("1"); System.out.printf(one.toString()); }
注意:
- 在接口方法的参数前加 @Param属性,注意 尽量每个参数都写,养成好的习惯和代码规范,Sql语句编写的时候,直接取@Param中设置的值即可,不需要单独设置参数类型
- 使用万能的Map,在接口方法中,参数直接传递Map;编写sql语句的时候,需要指定传递参数类型parameterType,参数类型为map,在使用方法的时候,Map的 key 为 sql中取的值即可,没有顺序要求!非常适用参数较多的情况。
insert
insert标签是做插入和新增数据操作的,其中的属性和select差不太多。
实例:新增student数据
-
书写dao层接口
public interface ExampleDao { Student getOne(); Student getOneById(@Param("id")String id); int addOne(Student student); }
-
书写mapper.xml文件中的sql
<insert id="addOne" parameterType="com.example.bean.Student"> insert into student(id,name,age) value (#{id},#{name},#{age}) </insert>
-
编写测试用例
@Test public void addOne() throws IOException { SqlSession sqlSession = MybatisUtils.getSqlSession(); ExampleDao mapper = sqlSession.getMapper(ExampleDao.class); Student student = new Student("2","222",23); int one = mapper.addOne(student); System.out.printf(one+""); sqlSession.commit(); }
注意:增删改必须提交事务:sqlSession.commit();
update
update标签做更新操作
实例:更新student表中id为1的数据。
-
书写dao层接口
public interface ExampleDao { Student getOne(); Student getOneById(@Param("id")String id); int addOne(Student student); int updateById(Student student); }
-
书写mapp.xml文件中的sql
<update id="updateById" parameterType="com.example.bean.Student"> update student set name = #{name},age= #{age} where id = #{id} </update>
-
编写测试用例
@Test public void updateById() throws IOException { SqlSession sqlSession = MybatisUtils.getSqlSession(); ExampleDao mapper = sqlSession.getMapper(ExampleDao.class); Student student = new Student("2","333",41); int one = mapper.updateById(student); System.out.printf(one+""); sqlSession.commit(); }
delete
delete标签是用来删除数据的
实例:根据条件删除student表数据
-
书写dao层接口
public interface ExampleDao { Student getOne(); Student getOneById(@Param("id")String id); int addOne(Student student); int updateById(Student student); int deleteByInfo(Student student); }
-
书写mapp.xml文件中的sql
<delete id="deleteByInfo" parameterType="com.example.bean.Student"> delete from student where id = #{id} </delete>
-
编写测试用例
@Test public void deleteByInfo() throws IOException { SqlSession sqlSession = MybatisUtils.getSqlSession(); ExampleDao mapper = sqlSession.getMapper(ExampleDao.class); Student student = new Student("2","333",41); int one = mapper.deleteByInfo(student); System.out.printf(one+""); sqlSession.commit(); }
中级
配置文件
核心配置文件
在mybatis中的核心配置文件是mybatis-config.xml ,通过该文件可以配置mybatis的一些核心功能。
核心配置项如下:
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
属性(properties)
通过配置属性可以将mybatis-config.xml中的一些配置信息抽离出来房子啊单独的文件中或者定义成变量,并可以进行动态替换。
//创建mysql.properties文件,将相关信息提出来
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://10.36.2.65:6612/ta
password=talent
<?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属性引入外部配置文件-->
<properties resource="mysql.properties">
<!--内部配置变量-->
<property name="username" value="root"/>
</properties>
<!--数据库链接配置-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--mysql驱动-->
<property name="driver" value="${driver}"/>
<!--mysql链接url-->
<property name="url" value="${url}"/>
<!--mysql用户名-->
<property name="username" value="${username}"/>
<!--密码-->
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="example.xml"/>
</mappers>
</configuration>
如上是通过在mybatis-config.xml中使用properties标签的resource属性将外部配置文件引入
除了这种方式还有另外的两种方式
也可以在 SqlSessionFactoryBuilder.build() 方法中传入属性值。例如:
1.SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
2.SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);
//通过这两行代码可以看到我们可以指定外部配置文件,也可指定生效的数据源。
如果一个配置项在多个地方进行了配置,加载顺序如下:
- 首先读取在 properties 元素体内指定的属性。
- 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
从 MyBatis 3.4.2 开始,你可以为占位符指定一个默认值。例如:
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${username:ut_user}"/> <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' -->
</dataSource>
这个特性默认是关闭的。要启用这个特性,需要添加一个特定的属性来开启这个特性。例如:
<properties resource="org/mybatis/example/config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- 启用默认值特性 -->
</properties>
environment
environment是数据源配置,通过观察配置文件可以看到可以在environments节点中配置多套数据源信息,但是生效的只能有一套,通过在environments节点的default属性进行指定。
-
子元素节点:transactionManager - [ 事务管理器 ]
<transactionManager type="[ JDBC | MANAGED ]"/>
-
子元素节点:dataSource,数据源配置,必须配置
其中属性type用于指定数据源类型,内置的数据源类型有三种 UNPOOLED 、 POOLED 、 JNDI
- UNPOOLED :每次请求都会打开和关闭,在企业级应用中性能比较差
- POOLED :提出了池的概念,每次请求都会去池中获取链接,使用完成后就会将连接放入到池中。
- JNDI:这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
- 还有一些第三方的数据源类型:比如dbcp,c3p0,druid等等….
设置(settings)
完整的 settings 元素的示例如下:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字,然后在resoultType等地方使用缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
</typeAliases>
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
每一个在包 domain.blog
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author
的别名为 author
;若有注解,则别名为其注解值。见下面的例子:
@Alias("author")
public class Author {
...
}
映射器(mappers)
有三种方式注册mapper.xml文件
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
//注意这种方式必须将xml文件和dao接口放在同一目录下,需要配置文件名称和接口名称一致,否则报错
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 但是需要配置文件名称和接口名称一致,并且位于同一目录下-->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
resultMap
resultMap的主要作用是解决数据库字段名和bean类属性名不一致的问题。
也能解决一些复杂的一对多和多对一的复杂查询.
测试实例:
-
我们将student表的age字段修改成rel_age。
-
书写dao层接口
public interface ExampleDao { Student getOne(); }
-
书写mapper.xml文件resultMap和select
<mapper namespace="com.example.dao.ExampleDao"> <resultMap id="student" type="com.example.bean.Student"> <!--使用result字段解决数据库表字段和实体类字段不一致 property代表实体类字段 column代表表字段 --> <result property="age" column="rel_age"></result> </resultMap> <select id="getOne" resultMap="student"> select * from student limit 0,1 </select> </mapper>
-
书写测试用例
@Test public void getOne() throws IOException { SqlSession sqlSession = MybatisUtils.getSqlSession(); ExampleDao mapper = sqlSession.getMapper(ExampleDao.class); Student one = mapper.getOne(); System.out.printf(one.toString()); }
分页查询
分页查询我们通常有以下几种方式:针对mysql数据库
- limit关键字--基于sql层面实现分页查询
- RowBounds类--基于java代码层面实现分页查询
- PageHelper插件--基于第三方插件实现分页查询
我们在此处重点演示基于RowBounds实现分页查询的操作.
-
书写dao层接口
public interface ExampleDao { List<Student> getAll(); }
-
书写mapper.xml中的sql
<select id="getAll" resultType="com.example.bean.Student"> select * from student; </select>
-
书写测试用例
@Test public void getALL() throws IOException { SqlSession sqlSession = MybatisUtils.getSqlSession(); int currentPage = 2; //第几页 int pageSize = 2; //每页显示几个 RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize); List<Student> students = sqlSession.selectList("com.example.dao.ExampleDao.getAll", null, rowBounds); System.out.printf(String.valueOf(students)); }
注解开发
mybatis最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的。在MyBatis 3后提供了新的基于注解的配置。Java 注解的的表达力和灵活性十分有限。最强大的 MyBatis 映射并不能用注解来构建
sql 类型主要分成:
- @select()
- @update()
- @insert()
- @delete()
括号中书写sql,参数接收可在xml中一致
高级
多对一
在resultMap标签中使用association标签
比如:
public class Student {
private int id;
private String name;
//多个学生可以是同一个老师,即多对一
private Teacher teacher;
}
在mapper.xml文件中编写查询,获取所有的学生信息(包括学生信息中对应的老师信息)
- 方式一:通过嵌套查询的方式,在association标签中通过select属性绑定了另一个查询.
<mapper namespace="com.kuang.mapper.StudentMapper">
<!--
需求:获取所有学生及对应老师的信息
思路:
1. 获取所有学生的信息
2. 根据获取的学生信息的老师ID->获取该老师的信息
3. 思考问题,这样学生的结果集中应该包含老师,该如何处理呢,数据库中我们一般使用关联查询?
1. 做一个结果集映射:StudentTeacher
2. StudentTeacher结果集的类型为 Student
3. 学生中老师的属性为teacher,对应数据库中为tid。
多个 [1,...)学生关联一个老师=> 一对一,一对多
4. 查看官网找到:association – 一个复杂类型的关联;使用它来处理关联查询
-->
<select id="getStudents" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<!--
这里传递过来的id,只有一个属性的时候,下面可以写任何值
association中column多参数配置:
column="{key=value,key=value}"
其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
-->
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
</select>
</mapper>
-
方式二:通过处理查询结果实现
<!-- 按查询结果嵌套处理 思路: 1. 直接查询出结果,进行结果集的映射 --> <select id="getStudents2" resultMap="StudentTeacher2" > select s.id sid, s.name sname , t.name tname from student s,teacher t where s.tid = t.id </select> <resultMap id="StudentTeacher2" type="Student"> <id property="id" column="sid"/> <result property="name" column="sname"/> <!--关联对象property 关联对象在Student实体类中的属性--> <association property="teacher" javaType="Teacher"> <result property="name" column="tname"/> </association> </resultMap>
一对多
在resultMap标签中使用collection标签
比如:
public class Teacher {
private int id;
private String name;
//一个老师多个学生
private List<Student> students;
}
实例:实现获取指定老师,及老师下的所有学生
-
方式一:通过处理查询结果实现
<mapper namespace="com.kuang.mapper.TeacherMapper"> <!-- 思路: 1. 从学生表和老师表中查出学生id,学生姓名,老师姓名 2. 对查询出来的操作做结果集映射 1. 集合的话,使用collection! JavaType和ofType都是用来指定对象类型的 JavaType是用来指定pojo中属性的类型 ofType指定的是映射到list集合属性中pojo的类型。 --> <select id="getTeacher" resultMap="TeacherStudent"> select s.id sid, s.name sname , t.name tname, t.id tid from student s,teacher t where s.tid = t.id and t.id=#{id} </select> <resultMap id="TeacherStudent" type="Teacher"> <result property="name" column="tname"/> <collection property="students" ofType="Student"> <result property="id" column="sid" /> <result property="name" column="sname" /> <result property="tid" column="tid" /> </collection> </resultMap> </mapper>
-
方式二:通过嵌套查询实现,通过在collection标签中使用select属性绑定子查询
<select id="getTeacher2" resultMap="TeacherStudent2"> select * from teacher where id = #{id} </select> <resultMap id="TeacherStudent2" type="Teacher"> <!--column是一对多的外键 , 写的是一的主键的列名--> <collection property="students" javaType="ArrayList" ofType="Student" column="id" select="getStudentByTeacherId"/> </resultMap> <select id="getStudentByTeacherId" resultType="Student"> select * from student where tid = #{id} </select>
注意:
JavaType和ofType都是用来指定对象类型的
- JavaType是用来指定pojo中属性的类型
- ofType指定的是映射到list集合属性中pojo的类型。
动态sql&sql片段
这块内容不想写了,以后在写吧
mybatis缓存
什么是缓存
将经常查询的数据存放在内存中
为什么需要缓存
频繁的和数据库交互是非常降低性能的,所以可以将经常查询且不常改变的数据放入内存中,我们获取数据时去内存中获取数据.
mybatis中的缓存
在mybatis中分为一级缓存和二级缓存.
-
一级缓存:默认情况下是开启的,SqlSession级别的缓存,也称为本地缓存
可以通过打印日志发现,对于同一个sqlSession进行的同一查询,会发现只和数据库交互了一次,但是对于不同的SqlSession,会交互多次.
一级缓存失效:
- SqlSession调用了close方法
- 对于同一SqlSession,执行了增删改操作后,缓存也会失效.
- SqlSession调用了clearCache()方法手动清理缓存.
-
二级缓存:二级缓存需要手动开启,是基于namespace的缓存,也就是说在同一namespace的mapper.xml文件中.
因为一级缓存的作用域太低了,所以有了二级缓存.在一个namespace下对应一个二级缓存.
二级缓存生效:开启二级缓存后,当一级缓存关闭后,也就是调用了close后,会将数据放入二级缓存.
不同的mapper查出的数据会放在自己对应的缓存(map)中;
-
为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
二级缓存使用
-
开启二级缓存
在mybatis-config.xml配置文件中添加缓存开启配置
<setting name="cacheEnabled" value="true"/>
-
在mapper.xml中配置使用二级缓存
<cache eviction="FIFO" //缓存清除策略 flushInterval="60000" //缓存刷新间隔 size="512" //缓存可以存放的数目 readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
可用的清除策略有:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
默认的清除策略是 LRU。
mybatis执行流程图
这个图在www.kuangstudy.com/zl/ssm#head….
源码分析
这块之后再写