Mybatis之一级缓存(七)
1. 介绍
Mybatis缓存分为一级缓存和二级缓存,在本节中我们介绍下一级缓存的使用及其特性
MyBatis的一级缓存是在一个Session域内有效的,当Session关闭后,缓存内容也随之销毁。缓存的存在使得我们再多次执行相同查询时减少了数据库交互次数,从而减少数据库带来的压力。
2. log4j的学习和使用
1)log4j介绍
日志是应用软件中不可缺少的部分,Apache的开源项目log4j是一个功能强大的日志组件,提供方便的日志记录。在apache网站:http://logging.apache.org/log4j/2.x/可以免费下载到Log4j最新版本的软件包。
2) 使用实例
首先,我们下载log4j的jar包,并导入到我们的项目中。
然后,在src根目录中建立log4j.properties,内容如下(相关配置选项请看注释内容):
#只输出到了控制台(stdOut)未输出到文件(fileOut)
log4j.rootLogger=DEBUG,stdOut
####################################### stdOut ##########################################
#配置日志输出
#org.apache.log4j.ConsoleAppender 输出到控制台
#org.apache.log4j.FileAppender 输出到文件
#org.apache.log4j.DailyRollingFileAppender 输出到文件(每天一个文件)
#org.apache.log4j.RollingFileAppender 输出到文件(文件大小达到指定尺寸后产生一个新的文件)
#org.apache.log4j.WriterAppender 输出流
log4j.appender.stdOut=org.apache.log4j.ConsoleAppender
#配置日志输出参数
log4j.appender.stdOut.Target=System.Out
#配置日志布局
#org.apache.log4j.HTMLLayout 以HTML表格形式布局
#org.apache.log4j.PatternLayout 自定义布局
#org.apache.log4j.SimpleLayout 包含日志信息的界别和信息字符串
#org.apache.log4j.TTCCLayout 包含日志产生的时间、线程、类别等等
log4j.appender.stdOut.layout=org.apache.log4j.PatternLayout
#配置自定义输出格式
#%m 输出文本信息
#%p 输出优先级,即OFF,FATAL,ERROR,WARN,INFO,DEBUG,ALL
#%r 输出自应用启动搞输出该log信息耗费的毫秒数
#%c 输出所属的类,通常是类全名
#%t 输出产生该日志时间的线程名
#%n 输出一个回车换行
#%d 输出日志产生时间
#%l 输出日志时间发生的位置,包含类名、线程及代码中的行数
log4j.appender.stdOut.layout.ConversionPattern= %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c %m %n
####################################### fileOut ##########################################
log4j.appender.fileOut=org.apache.log4j.FileAppender
log4j.appender.fileOut.File=F://DEGUG.LOG
log4j.appender.fileOut.Append=true
log4j.appender.fileOut.Threshold=DEBUG
log4j.appender.fileOut.layout=org.apache.log4j.PatternLayout
log4j.appender.fileOut.layout.ConversionPattern= %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] %c %m %n
完成上面的内容以后,Mybatis会将SQL查询日志输出到控制台中以方便我们查看。
3. Mybatis一级缓存学习
1)数据库准备
CREATE TABLE tbCache1(
ID INT IDENTITY(1,1),
Txt NVARCHAR(100)
PRIMARY KEY(ID)
) CREATE TABLE tbCache2(
ID INT IDENTITY(1,1),
Txt NVARCHAR(100)
PRIMARY KEY(ID)
) INSERT INTO tbCache1(Txt)
SELECT '' UNION
SELECT '' UNION
SELECT '' UNION
SELECT '' INSERT INTO tbCache2(Txt)
SELECT 'aaa' UNION
SELECT 'bbb' UNION
SELECT 'ccc' UNION
SELECT 'ddd'
我们创建了两个数据表,分别为tbCache1和tbCache2,以便后续测试使用。
2)JavaBean实体类(创建com.mybatis.entity.CacheInfo)
package com.mybatis.entity;
public class CacheInfo {
private Integer id;
private String txt;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTxt() {
return txt;
}
public void setTxt(String txt) {
this.txt = txt;
}
}
3)DAO层准备
首先,我们需要创新一个新的DAO接口,com.mybatis.dao.CacheDao
package com.mybatis.dao;
import com.mybatis.entity.CacheInfo;
public interface CacheDao {
public CacheInfo getCache1(int id);
public CacheInfo getCache2(int id);
public void updateCache1(CacheInfo cacheInfo);
public void updateCache2(CacheInfo cacheInfo);
}
其次,为com.mybatis.dao.CacheDao增加对应的Mapper实现(com\mybatis\dao\mapper\CacheMapper.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.dao.CacheDao">
<select id="getCache1" parameterType="int" resultType="com.mybatis.entity.CacheInfo">
SELECT * FROM tbCache1 WHERE ID=#{id}
</select>
<select id="getCache2" parameterType="int" resultType="com.mybatis.entity.CacheInfo">
SELECT * FROM tbCache2 WHERE ID=#{id}
</select> <update id="updateCache1" parameterType="com.mybatis.entity.CacheInfo">
UPDATE tbCache1 SET Txt=#{txt} WHERE ID=#{id}
</update>
<update id="updateCache2" parameterType="com.mybatis.entity.CacheInfo">
UPDATE tbCache2 SET Txt=#{txt} WHERE ID=#{id}
</update>
</mapper>
4) 测试Mybatis一级缓存特性
我们再Main方法中增加了三个测试函数(test1,test2,test3),并分别执行后观看效果,源代码如下:
package com.mybatis; import java.io.InputStream; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder; import com.mybatis.entity.CacheInfo; @SuppressWarnings("unused")
public class TestMain {
private static void test1(SqlSession session) {
CacheInfo cacheInfo;
//多次查询数据表
System.out.println("-------------------------第一次测试开始-------------------------");
cacheInfo = session.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
System.out.println("第1次打印 ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
cacheInfo = session.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
System.out.println("第2次打印 ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
cacheInfo = session.selectOne("com.mybatis.dao.CacheDao.getCache1", 2);
System.out.println("第3次打印 ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
cacheInfo = session.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
System.out.println("第4次打印 ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
session.clearCache();
System.out.println("清除缓存完成");
cacheInfo = session.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
System.out.println("第5次打印 ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
System.out.println("-------------------------第一次测试结束-------------------------");
} private static void test2(SqlSession session) {
CacheInfo cacheInfo;
//先查询数据表tbCache1中ID=1的记录,在修改数据表tbCache1中ID=1的记录,再重新查询数据表tbCache1中ID=1的记录
System.out.println("-------------------------第二次测试开始-------------------------");
cacheInfo = session.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
System.out.println("第1次打印 ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
cacheInfo = new CacheInfo();
cacheInfo.setId(1);
cacheInfo.setTxt("11111");
session.update("com.mybatis.dao.CacheDao.updateCache1", cacheInfo);
System.out.println("修改数据完成");
cacheInfo = session.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
System.out.println("第2次打印 ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
System.out.println("-------------------------第二次测试结束-------------------------");
} private static void test3(SqlSession session) {
CacheInfo cacheInfo;
//先查询数据表tbCache1中ID=1的记录,在修改数据表tbCache2中ID=1的记录,再重新查询数据表tbCache1中ID=1的记录
System.out.println("-------------------------第三次测试开始-------------------------");
cacheInfo = session.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
System.out.println("第1次打印 ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
cacheInfo = new CacheInfo();
cacheInfo.setId(1);
cacheInfo.setTxt("aaaaa");
session.update("com.mybatis.dao.CacheDao.updateCache2", cacheInfo);
System.out.println("修改数据完成");
cacheInfo = session.selectOne("com.mybatis.dao.CacheDao.getCache1", 1);
System.out.println("第2次打印 ID:"+cacheInfo.getId()+","+cacheInfo.getTxt());
System.out.println("-------------------------第三次测试结束-------------------------");
} public static void main(String[] args) {
InputStream iStream = TestMain.class.getClassLoader().getResourceAsStream("mybatis.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(iStream);
SqlSession session = sessionFactory.openSession(); test1(session);
test2(session);
test3(session); session.close();
}
}
打印结果为:
-----------------------------第一次测试开始-----------------------------
-- ::06.606 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction Opening JDBC Connection
-- ::06.892 [DEBUG] org.apache.ibatis.datasource.pooled.PooledDataSource Created connection .
-- ::06.893 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction Setting autocommit to false on JDBC Connection [ConnectionID: ClientConnectionId: edb9ecad-b03c-45fc-a7e3-6caca7828f9b]
-- ::06.895 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Preparing: SELECT * FROM tbCache1 WHERE ID=?
-- ::06.954 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Parameters: (Integer)
-- ::07.021 [DEBUG] com.mybatis.dao.CacheDao.getCache1 <== Total:
第1次打印 ID:,
第2次打印 ID:,
-- ::07.030 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Preparing: SELECT * FROM tbCache1 WHERE ID=?
-- ::07.031 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Parameters: (Integer)
-- ::07.032 [DEBUG] com.mybatis.dao.CacheDao.getCache1 <== Total:
第3次打印 ID:,
第4次打印 ID:,
清除缓存完成
-- ::07.032 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Preparing: SELECT * FROM tbCache1 WHERE ID=?
-- ::07.033 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Parameters: (Integer)
-- ::07.033 [DEBUG] com.mybatis.dao.CacheDao.getCache1 <== Total:
第5次打印 ID:,
-----------------------------第一次测试结束----------------------------- -----------------------------第二次测试开始-----------------------------
-- ::53.083 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction Opening JDBC Connection
-- ::53.374 [DEBUG] org.apache.ibatis.datasource.pooled.PooledDataSource Created connection .
-- ::53.374 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction Setting autocommit to false on JDBC Connection [ConnectionID: ClientConnectionId: 668b5f8e-13ad--b058-cd8dbe08fbcc]
-- ::53.378 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Preparing: SELECT * FROM tbCache1 WHERE ID=?
-- ::53.436 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Parameters: (Integer)
-- ::53.502 [DEBUG] com.mybatis.dao.CacheDao.getCache1 <== Total:
第1次打印 ID:,
-- ::53.512 [DEBUG] com.mybatis.dao.CacheDao.updateCache1 ==> Preparing: UPDATE tbCache1 SET Txt=? WHERE ID=?
-- ::53.512 [DEBUG] com.mybatis.dao.CacheDao.updateCache1 ==> Parameters: (String), (Integer)
-- ::53.513 [DEBUG] com.mybatis.dao.CacheDao.updateCache1 <== Updates:
修改数据完成
-- ::53.514 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Preparing: SELECT * FROM tbCache1 WHERE ID=?
-- ::53.514 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Parameters: (Integer)
-- ::53.515 [DEBUG] com.mybatis.dao.CacheDao.getCache1 <== Total:
第2次打印 ID:,
-----------------------------第二次测试结束----------------------------- -----------------------------第三次测试开始-----------------------------
-- ::21.667 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction Opening JDBC Connection
-- ::21.952 [DEBUG] org.apache.ibatis.datasource.pooled.PooledDataSource Created connection .
-- ::21.953 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction Setting autocommit to false on JDBC Connection [ConnectionID: ClientConnectionId: e9725d9f-04d1-450a-86c7-c1c77c1bc70e]
-- ::21.956 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Preparing: SELECT * FROM tbCache1 WHERE ID=?
-- ::22.012 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Parameters: (Integer)
-- ::22.082 [DEBUG] com.mybatis.dao.CacheDao.getCache1 <== Total:
第1次打印 ID:,
-- ::22.093 [DEBUG] com.mybatis.dao.CacheDao.updateCache2 ==> Preparing: UPDATE tbCache2 SET Txt=? WHERE ID=?
-- ::22.093 [DEBUG] com.mybatis.dao.CacheDao.updateCache2 ==> Parameters: aaaaa(String), (Integer)
-- ::22.094 [DEBUG] com.mybatis.dao.CacheDao.updateCache2 <== Updates:
修改数据完成
-- ::22.095 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Preparing: SELECT * FROM tbCache1 WHERE ID=?
-- ::22.095 [DEBUG] com.mybatis.dao.CacheDao.getCache1 ==> Parameters: (Integer)
-- ::22.096 [DEBUG] com.mybatis.dao.CacheDao.getCache1 <== Total:
第2次打印 ID:,
-----------------------------第三次测试结束-----------------------------
5)测试结论
在第一次测试中:
1. 对比“第1次打印”和“第2次打印”可以发现,“第1次打印”进行了数据库查询,而“第2次打印”则没有,说明“第1次打印”的时候使用了缓存。也就是说:在一个Session域内,多次重复执行同一个查询,会使用缓存。
2. 对比“第3次打印”和“第2次打印”可以发现,因为“第3次打印”更换了查询参数,所以需要进行数据库查询。也就是说:在一个Session域内,不同参数下的同一个查询重复执行,不会使用缓存。
3. 对比“第3次打印”和“第4次打印”可以发现,“第4次打印”的时候依然使用了“第1次打印”时候的缓存。也就是说:在一个Session域内,执行查询的时候默认是不会清除现有缓存的。同一个查询的在不同参数下,会有多份缓存的存在。
4. 对比“第1次打印”和“第5次打印”可以发现,在一个Session域内,清除缓存以后则需要新的数据库查询。
在第二次测试中:
1. 对比“第1次打印”和“第2次打印”可以发现,在两次打印之间的数据修改,导致了缓存清除,“第2次打印”需要重新进行数据库查询。
在第三次测试中:
1. 对比“第1次打印”和“第2次打印”可以发现,在两次打印之间,尽管我们做了其他表的数据修改(要查询的数据表是tbCache1,而修改的数据表是tbCache2),“第2次打印”依然需要重新进行数据库查询。
总和第二次和第三次测试,我们可以得到结论:在一个Session域内,执行增删改操作会清除所有的缓存。而不管增删改操作是否真的影响到我们要查询到的数据。
4)总结
如果你觉得上面的结论理解起来比较困难,你可以参考下面的理解方式:
在一个session域内,session的select***方法(例如:selecetOne、selectList等)会产生缓存,并且执行select****的时候,不同的参数会产生不同的缓存。
在一个session域内,session的insert***、update***、delete***等会清除缓存,实际上,所有需要commit操作的session方法都会清除缓存。
5)后记
在实际中,我们往往把Bybatis和Spring进行整合使用。但是很遗憾,整合以后的Mybatis的一级缓存是不能使用的。Mybatis和Spring整合以后,每执行一次查询操作都需要Open一个新的Session,并且在查询结束后会Close这个Sesison,而Mybatis的一级缓存只作用于一个Session域内,也就是说:mybatis的一级缓存在spring中是没有作用的。
Mybatis之一级缓存(七)的更多相关文章
- [原创]关于mybatis中一级缓存和二级缓存的简单介绍
关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...
- SSM-MyBatis-17:Mybatis中一级缓存(主要是一级缓存存在性的证明,增删改对一级缓存会造成什么影响)
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 缓存------------------------------------------> 很熟悉的一个 ...
- MyBatis的一级缓存和二级缓存简介笔记
关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...
- spring管理hibernate,mybatis,一级缓存失效原因
mybatis缓存:一级缓存和二级缓存 hibernate缓存:一级缓存和二级缓存 关于缓存: 缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器, 其作用是为了减少应 ...
- 关于mybatis中一级缓存和二级缓存的简单介绍
关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...
- 《深入理解mybatis原理6》 MyBatis的一级缓存实现详解 及使用注意事项
<深入理解mybatis原理> MyBatis的一级缓存实现详解 及使用注意事项 0.写在前面 MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓 ...
- MyBatis 学习记录4 MyBatis的一级缓存
主题 分享记录一下MyBatis的一级缓存相关的学习. Demo public static void firstLevelCache() { init("mybatis-config.xm ...
- 《深入理解mybatis原理》 MyBatis的一级缓存实现详解 及使用注意事项
MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓存机制上.MyBatis提供了一级缓存.二级缓存 这两个缓存机制,能够很好地处理和维护缓存,以提高系统的性能.本 ...
- Mybatis的一级缓存和二级缓存的理解以及用法
程序中为什么使用缓存? 先了解一下缓存的概念:原始意义是指访问速度比一般随机存取存储器快的一种RAM,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术.对于我们编程来说,所谓的 ...
随机推荐
- NO4 find&mv-&-特殊符号..和.
问题七:退到上一级目录,删除data目录. 解答:cd ..或cd ../ rm -r data或rmdir data#空目录就不需要带-rf,杀鸡不用宰牛刀,rmdir基本要淘汰的命令 ...
- 2.8 学习总结 之 JQ初识
一.说在前面 昨天 学习了kotlin的相关知识 今天 学习JQ Jquery它是javascript的一个轻量级框架,对javascript进行封装,它提供了很多方便的选择器.供你快速定位到需要操作 ...
- Redis 详解 (六) RDB 持久化
目录 1.RDB 简介 2.触发方式 ①.自动触发 ②.手动触发 3.恢复数据 4.停止 RDB 持久化 5.RDB 的优势和劣势 6.RDB 自动保存的原理 前面我们说过,Redis 相对于 Me ...
- @echo off命令
在C盘下新建一个文本文档,将名字改为1.bat. 打开/编辑,输入call cmd.cmd是命令提示符.运行该文件,出现命令提示符窗口,在该窗口下可以运行各种命令.由图1.1可见,在第一行显示C:\ ...
- SpringMVC原理及流程解析
前言 春节期间宅在家里闲来无事,对SpringMVC进行了比较深入的了解,将之前模糊不清的地方基本摸索清楚了,特此撰文总结记录一下. 正文 一.一个请求为什么会调用到SpringMVC框架里? 首先问 ...
- 竟然把Ruoyi在我自己的Eclipse编译成功,并能跑通了。。。。服了我自己了
前几天,下载最新ECLISPSE2019压缩包,解压缩成功,没提示不是免费:eclipse-jee-2019-12-R-win32-x86_64.zip然后我配置好了maven于是我1月2日晚一时兴起 ...
- 135-PHP final类和方法都是不可被继承或覆盖的
<?php final class final_class{ //定义final修饰的类 } class myclass extends final_class{ //试图继承final修饰的类 ...
- 深度解析高分Essay写作组成部分
很多留学生在国外呆了好几个学期对于怎么写Essay还是不太了解,今天小编大致总结了以下一些技巧,相信同学们可以尝试着自己完成一篇Essay写作!一起来看看吧! 与你的导师沟通 你的导师对于你的Essa ...
- 逆向--C函数和汇编
C函数和汇编 C代码 (编译工具gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609平台ubuntu i386 32位) int bar(int c ...
- Elasticsearch 使用集群 - 删除索引
章节 Elasticsearch 基本概念 Elasticsearch 安装 Elasticsearch 使用集群 Elasticsearch 健康检查 Elasticsearch 列出索引 Elas ...