MyBatis——(五)缓存

2018-11-30 20:03:00     

缓存介绍

正如大多数持久层框架一样,MyBatis 同样提供了一级缓存二级缓存的支持

  • 一级缓存:基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空
  • 二级缓存:与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache
  • 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear

一级缓存

1. 在session中查询两次id=1的teacher对象,如下代码:

// 查询所有
@Test
public void testOne() throws IOException {
	// 获取配置文件
	String resource = "config/mybatis-config.xml";
	// 利用一个叫Resources的类的getResourceAsStream方法从配置文件xml中获取里面的内容资源
	InputStream is = Resources.getResourceAsStream(resource);
	// 然后用SqlSessionFactoryBuilder工厂构建者把获取的资源传进去就构建出了我们需要使用的工厂
	SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
	// 工厂生产产品
	SqlSession session = sessionFactory.openSession();
	// 产品实现相应的功能(listTeacher这个就是在配置文件teacher.xml中那条sql语句设置的id)
	Teacher list = session.selectOne("listTeacher", 1);
	System.out.println(list);
	// 产品实现相应的功能(listTeacher这个就是在配置文件teacher.xml中那条sql语句设置的id)
	Teacher list2 = session.selectOne("listTeacher", 1);
	System.out.println(list2);
	session.commit();
	// 使用session执行完SQL之后需要关闭session
	session.close();
}

执行结果,第一次会去数据库中取数据,但是第二次就不会访问数据库了,而是直接从session中取出来。

11:31:41.336 [main] DEBUG config.listTeacher - ==>  Preparing: select * from teacher where id=? 
11:31:41.349 [main] DEBUG config.listTeacher - ==> Parameters: 1(Integer)
11:31:41.358 [main] TRACE config.listTeacher - <==    Columns: id, name
11:31:41.358 [main] TRACE config.listTeacher - <==        Row: 1, 数学老师
11:31:41.360 [main] DEBUG config.listTeacher - <==      Total: 1
Teacher [id=1, name=数学老师]
11:31:41.360 [main] DEBUG config - Cache Hit Ratio [config]: 0.0
Teacher [id=1, name=数学老师]

2. 这次创建两个session,分别在session中查询两次id=1的teacher对象,如下代码:

// 查询所有
@Test
public void testOne() throws IOException {
	// 获取配置文件
	String resource = "config/mybatis-config.xml";
	// 利用一个叫Resources的类的getResourceAsStream方法从配置文件xml中获取里面的内容资源
	InputStream is = Resources.getResourceAsStream(resource);
	// 然后用SqlSessionFactoryBuilder工厂构建者把获取的资源传进去就构建出了我们需要使用的工厂
	SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
	// 工厂生产产品
	SqlSession session = sessionFactory.openSession();
	// 产品实现相应的功能(listTeacher这个就是在配置文件teacher.xml中那条sql语句设置的id)
	Teacher list = session.selectOne("listTeacher", 1);
	System.out.println(list);
	session.commit();
	// 使用session执行完SQL之后需要关闭session
	session.close();
	// 工厂生产产品
	SqlSession session2 = sessionFactory.openSession();
	// 产品实现相应的功能(listTeacher这个就是在配置文件teacher.xml中那条sql语句设置的id)
	Teacher list2 = session2.selectOne("listTeacher", 1);
	System.out.println(list2);
	session2.commit();
	// 使用session执行完SQL之后需要关闭session
	session2.close();
}

执行结果,第一次会去数据库中取数据,第二次还是会去数据库中取数据,这就证明了一级缓存是在session里的。

二级缓存

mybatis-config.xml配置文件中加入二级缓存设置,如下代码:

<!-- 设置二级缓存 -->
<settings>
   <setting name="cacheEnabled" value="true" />
</settings>

Teacher.xml文件中也要设置二级缓存,注意到 useCache="true" 了吗?表示该select可以(默认)使用缓存。也可以设置为useCache="false"表示该sql不支持缓存。 如下代码:

<mapper namespace="config">
	<!-- 设置二级缓存 -->
	<cache />
	<!-- resultType标签本应写dao.Teacher(包名+类名) -->
	<!-- 因为在mybatis-config.xml里配置了typeAliases标签所以这里直接写类名就行 -->
	<select id="listTeacher" parameterType="_int" resultType="Teacher" useCache="true">
		select * from teacher where id=#{id}
	</select>
</mapper>

序列化Teacher对象,如下代码:

package dao;

import java.io.Serializable;

public class Teacher implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private int id;
	private String name;

	@Override
	public String toString() {
		return "Teacher [id=" + id + ", name=" + name + "]";
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

再次运行测试,发现二级缓存生效。在同一个SessionFactory下查询id=1的数据,只有第一次需要执行sql语句,以后都是从缓存中取出

11:51:48.974 [main] DEBUG config.listTeacher - ==>  Preparing: select * from teacher where id=? 
11:51:48.987 [main] DEBUG config.listTeacher - ==> Parameters: 1(Integer)
11:51:48.995 [main] TRACE config.listTeacher - <==    Columns: id, name
11:51:48.995 [main] TRACE config.listTeacher - <==        Row: 1, 数学老师
11:51:48.997 [main] DEBUG config.listTeacher - <==      Total: 1
Teacher [id=1, name=数学老师]
11:51:49.032 [main] DEBUG config - Cache Hit Ratio [config]: 0.5
Teacher [id=1, name=数学老师]

二级缓存补充说明

  1. 映射语句文件中的所有select语句将会被缓存。

  2. 映射语句文件中的所有insert,update和delete语句会刷新缓存。

  3. 缓存会使用Least Recently Used(LRU,最近最少使用的)算法来收回。

  4. 缓存会根据指定的时间间隔来刷新。

  5. 缓存会存储1024个对象

cache标签常用属性:

<cache 
eviction="FIFO"  <!--回收策略为先进先出-->
flushInterval="60000" <!--自动刷新时间60s-->
size="512" <!--最多缓存512个引用对象-->
readOnly="true"/> <!--只读-->
ps:本篇博客源码下载链接:https://pan.baidu.com/s/1dREJbTdoWvI4lmcs1fyZDA密码:4kcf
MyBatis——(六)逆向工程

MyBatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代码(mapper.xml、mapper.java、pojo...)。一般在开发中,通过数据库中的单表,自动生成java代码,这样能够大大减少我们平时开发的工作量

SSM——整合Spring+SpringMVC+Mybatis

Spring:用到注解和自动装配,就是Spring的两个精髓IOC(反向控制)和 AOP(面向切面编程)。 SpringMVC:用到了MVC模型,将流程控制代码放到Controller层处理,将业务逻辑代码放到Service层处理。 Mybatis:用到了与数据库打交道的层面,dao(mapper)层,放在所有的逻辑之后,处理与数据库的CRUD相关的操作。

 发表评论