mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache
MyBatis(六)缓存机制之一级缓存
MyBatis(六)缓存机制之⼀级缓存⼀、⼀级缓存介绍 1、⼀级缓存(local cache),即本地缓存,作⽤域默认为SqlSession。
当 Session flush 或 close 后,该 session 中的所有 Cache 将被清空。
2、本地缓存不能被关闭,但可以调⽤ clearCache() 来清空本地缓存,或者改变缓存的作⽤域。
3、在 MyBatis3.1 之后,可以配置本地缓存的作⽤域,在 MyBatis.xml 中配置。
4、⼀级缓存是 sqlsession 级别的缓存。
⼀级缓存是⼀直开启的,sqlsession级别的⼀个 map,与数据库同⼀次会话期间查询到的数据会放在本地缓存中。
多个⼀级缓存中的数据不能共⽤。
以后如果需要获取相同的数据,直接从缓存中获取,不必再去查询数据库。
5、⼀级缓存的⼯作机制 同⼀次会话期间只要查询过的数据都会保存在当前的 SqlSession 的⼀个 Map 中 key:hashCode+查询的 SqlId + 编写的 sql 查询语句 + 参数⼆、⼀级缓存失效的四种情况 ⼀级缓存失效情况(没有使⽤到当前⼀级缓存的情况,效果就是,还需要再向数据发送SQL) 1、sqlSession 不同:使⽤不同的 sqlSession 数据库会话,不同的 SqlSession 对应不同的⼀级缓存; 2、sqlSession 相同:但查询条件不同(当前⼀级缓存中还没有这个数据) 3、如果sqlSession相同:两次查询之间执⾏了增删改操作(这次增删改可能对当前数据有影响) 4、如果sqlSession相同,⼿动清除了⼀级缓存(把缓存内容清空) SqlSession 级别的缓存就相当于⼀个 Map。
三、⼀级缓存演⽰ 1、在同⼀个 SqlSession 中查询同⼀条记录 代码:/*** mybatis中的⼀级缓存默认开启,是SqlSession级别的* 即同⼀个SqlSession对于⼀个sql语句,执⾏之后就会存储在缓存中,* 下次执⾏相同的sql,直接从缓存中取*/@Testpublic void testFirstLevelCache() throws IOException {SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();SqlSession sqlSession = sqlSessionFactory.openSession();try {EmployeeMapperCache mapper = sqlSession.getMapper(EmployeeMapperCache.class);Employee emp01 = mapper.getEmpById(1);System.out.println("emp01 = " + emp01);//处理业务Employee emp02 = mapper.getEmpById(1);System.out.println("emp02 = " + emp02);System.out.println(emp01 == emp02);} finally {sqlSession.close();}} 运⾏结果: 可以看出,查询的是同⼀条记录,但第⼀次是从数据库中查询的,有 SQL 语句,第⼆次查询是就是从缓存(SqlSession)中获取的。
缓存(一级缓存和二级缓存)
缓存(⼀级缓存和⼆级缓存)缓存可以将数据保存在内存中,是互联⽹系统常常⽤到的。
⽬前流⾏的缓存服务器有 MongoDB、Redis、Ehcache 等。
缓存是在计算机内存上保存的数据,读取时⽆需再从磁盘读⼊,因此具备快速读取和使⽤的特点。
和⼤多数持久化框架⼀样,MyBatis 提供了⼀级缓存和⼆级缓存的⽀持。
默认情况下,MyBatis 只开启⼀级缓存。
⼀级缓存⼀级缓存是基于 PerpetualCache(MyBatis⾃带)的 HashMap 本地缓存,作⽤范围为 session 域内。
当 session flush(刷新)或者close(关闭)之后,该 session 中所有的 cache(缓存)就会被清空。
在参数和 SQL 完全⼀样的情况下,我们使⽤同⼀个 SqlSession 对象调⽤同⼀个 mapper 的⽅法,往往只执⾏⼀次 SQL。
因为使⽤SqlSession 第⼀次查询后,MyBatis 会将其放在缓存中,再次查询时,如果没有刷新,并且缓存没有超时的情况下,SqlSession 会取出当前缓存的数据,⽽不会再次发送 SQL 到数据库。
由于 SqlSession 是相互隔离的,所以如果你使⽤不同的 SqlSession 对象,即使调⽤相同的 Mapper、参数和⽅法,MyBatis 还是会再次发送 SQL 到数据库执⾏,返回结果。
⽰例:WebsiteMapperpublic Website selectWebsiteById(int id);WebsiteMapper.xml<select id="selectWebsiteById"resultType="net.biancheng.po.Website">SELECT * FROM websiteWHERE id=#{id}</select>测试代码public class Test {public static Logger logger = Logger.getLogger(Test.class);public static void main(String[] args) throws IOException {InputStream config = Resources.getResourceAsStream("mybatis-config.xml"); // 根据配置⽂件构建SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(config);SqlSession ss = ssf.openSession();Website site = ss.selectOne("net.biancheng.mapper.WebsiteMapper.selectWebsiteById", 1);logger.debug("使⽤同⼀个sqlsession再执⾏⼀次");Website site2 = ss.selectOne("net.biancheng.mapper.WebsiteMapper.selectWebsiteById", 1);// 请注意,当我们使⽤⼆级缓存的时候,sqlSession调⽤了 commit⽅法后才会⽣效mit();logger.debug("现在创建⼀个新的SqlSeesion对象在执⾏⼀次");SqlSession ss2 = ssf.openSession();Website site3 = ss2.selectOne("net.biancheng.mapper.WebsiteMapper.selectWebsiteById", 1);// 请注意,当我们使⽤⼆级缓存的时候,sqlSession调⽤了 commit⽅法后才会⽣效mit();}}运⾏结果DEBUG [main] - ==> Preparing: SELECT * FROM website WHERE id=?DEBUG [main] - ==> Parameters: 1(Integer)DEBUG [main] - <== Total: 1DEBUG [main] - 使⽤同⼀个sqlsession再执⾏⼀次DEBUG [main] - 现在创建⼀个新的SqlSeesion对象在执⾏⼀次DEBUG [main] - ==> Preparing: SELECT * FROM website WHERE id=?DEBUG [main] - ==> Parameters: 1(Integer)DEBUG [main] - <== Total: 1从运⾏结果可以看出,第⼀个 SqlSession 实际只发⽣过⼀次查询,⽽第⼆次查询就从缓存中取出了,也就是 SqlSession 层⾯的⼀级缓存。
mybatis一级二级缓存原理
mybatis一级二级缓存原理
MyBatis 提供了两级缓存机制,即一级缓存和二级缓存。
这两级缓存的原理如下:
1. 一级缓存(SqlSession 级别的缓存):
一级缓存是在同一个 SqlSession 中,对于相同的查询条件,只会执行一次SQL 查询,查询结果被缓存起来,后续的相同查询可以直接从缓存中获取结果,避免了重复的数据库查询操作。
一级缓存是基于 SqlSession 对象的,也就是说,只要 SqlSession 不关闭,一级缓存就会一直存在。
2. 二级缓存(Mapper 级别的缓存):
二级缓存是跨 SqlSession 的,也就是说,即使在不同的 SqlSession 中,只要查询条件相同,就可以共享同一个查询结果。
二级缓存是基于 Mapper 接口的,可以在多个 Mapper 之间共享数据。
二级缓存可以配置为只对某些特定的 Mapper 或者全局启用。
MyBatis 的两级缓存机制可以有效地减少对数据库的访问次数,提高应用程序的性能。
但是需要注意的是,由于二级缓存是跨 SqlSession 的,因此在使用二级缓存时需要特别注意线程安全问题,以及在 SqlSession 关闭或者清空缓存时要正确地处理缓存数据。
MyBatis 缓存机制深度解剖
缓存概述∙正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持;∙一级缓存基于PerpetualCache的 HashMap 本地缓存,其存储作用域为Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
∙二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache、Hazelcast等。
∙对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
∙MyBatis 的缓存采用了delegate机制及装饰器模式设计,当put、get、remove时,其中会经过多层 delegate cache 处理,其Cache类别有:BaseCache(基础缓存)、EvictionCache(排除算法缓存) 、DecoratorCache(装饰器缓存):BaseCache :为缓存数据最终存储的处理类,默认为 PerpetualCache,基于Map存储;可自定义存储处理,如基于EhCache、Memcached等;EvictionCache :当缓存数量达到一定大小后,将通过算法对缓存数据进行清除。
默认采用 Lru 算法(LruCache),提供有 fifo 算法(FifoCache)等;DecoratorCache:缓存put/get处理前后的装饰器,如使用 LoggingCache 输出缓存命中日志信息、使用 SerializedCache 对 Cache的数据 put或get 进行序列化及反序列化处理、当设置flushInterval(默认1/h)后,则使用 ScheduledCache 对缓存数据进行定时刷新等。
带你深入理解MyBatis缓存机制
带你深⼊理解MyBatis缓存机制⽬录⼀、简介1、缓存机制介绍2. ⼀级缓存和⼆级缓存⼆、⼀级缓存三、⼆级缓存3.1 mybatis⾃带的⼆级缓存3.1.1 代码测试⼆级缓存3.1.2 查询结果存⼊⼆级缓存的时机3.1.3 ⼆级缓存相关配置四、整合EHCache4.1 EHCache简介4.2 整合操作五、缓存基本原理5.1 Cache接⼝5.2 PerpetualCache总结⼀、简介1、缓存机制介绍当客户端发起⼀次查询请求时,⾸先通过java程序进⾏⽹络传输访问mysql数据库及对应的数据的服务器硬盘,当第⼆次的请求也是查询相同的数据时再通过这个流程显然有点“浪费”上次请求访问到的资源,所以我们将第⼀次查询到的数据存到缓存区域,当发⽣下⼀次相同请求时直接在缓存区域拿就⾏了。
2. ⼀级缓存和⼆级缓存①使⽤顺序查询的顺序是:先查询⼆级缓存,因为⼆级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使⽤。
如果⼆级缓存没有命中,再查询⼀级缓存如果⼀级缓存也没有命中,则查询数据库SqlSession关闭之前,⼀级缓存中的数据会写⼊⼆级缓存②效⽤范围⼀级缓存:SqlSession级别⼆级缓存:SqlSessionFactory级别它们之间范围的⼤⼩参考下⾯图:⼆、⼀级缓存当使⽤相同查询条件查询数据时,⼀共只打印了⼀条SQL语句,两个变量指向同⼀个对象。
⼀级缓存失效的情况:不是同⼀个SqlSession同⼀个SqlSession但是查询条件发⽣了变化同⼀个SqlSession两次查询期间执⾏了任何⼀次增删改操作同⼀个SqlSession两次查询期间⼿动清空了缓存同⼀个SqlSession两次查询期间提交了事务三、⼆级缓存3.1 mybatis⾃带的⼆级缓存3.1.1 代码测试⼆级缓存①开启⼆级缓存功能在想要使⽤⼆级缓存的Mapper配置⽂件中加⼊cache标签<mapper namespace="com.zengchuiyu.mybatis.dao.EmployeeMapper"><!-- 启动⼆级缓存功能 --><cache/>②让实体类⽀持序列化public class Employee implements Serializable {③junit测试这个功能的测试操作需要将SqlSessionFactory对象设置为成员变量public class CacheTest {private SqlSessionFactory factory;@Beforepublic void init() throws IOException {factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));}//测试⼆级缓存,(mybatis⾃带的)@Testpublic void test1(){SqlSession session = factory.openSession();EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);Employee employee = mapper.selectEmpById(2);System.out.println("employee = " + employee);//在执⾏第⼆次查询前,关闭当前SqlSessionsession.close();//开启新的SqlSessionsession = factory.openSession();mapper = session.getMapper(EmployeeMapper.class);employee = mapper.selectEmpById(2);System.out.println("employee = " + employee);session.close();}}打印效果:22:48:18.669 [main] DEBUG com.zengchuiyu.mybatis.dao.EmployeeMapper - Cache Hit Ratio [com.zengchuiyu.mybatis.dao.EmployeeMapper]: 0.5④缓存命中率⽇志中打印的Cache Hit Ratio叫做缓存命中率Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.0(0/1)Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.5(1/2)Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.6666666666666666(2/3)Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.75(3/4)Cache Hit Ratio [com.atguigu.mybatis.EmployeeMapper]: 0.8(4/5)缓存命中率=命中缓存的次数/查询的总次数3.1.2 查询结果存⼊⼆级缓存的时机结论:SqlSession关闭的时候,⼀级缓存中的内容会被存⼊⼆级缓存3.1.3 ⼆级缓存相关配置eviction属性:缓存回收策略LRU(Least Recently Used) – 最近最少使⽤的:移除最长时间不被使⽤的对象。
Memcache资料
Memcache缓存1.MyBatis缓存MyBatis缓存分为一级缓存与二级缓存一级缓存:基于PerpetualCache 的HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有Cache 就将清空。
二级缓存:与一级缓存其机制相同,默认也是采用PerpetualCache,HashMap存储,不同在于其存储作用域为Mapper(Namespace)缓存更新机制:当某一作用域(一级缓存Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有select 中的缓存将被清空避免使用二级缓存:/isea533/article/details/445662572.Memcachea)简介Memcache 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。
它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。
Memcache基于一个存储键/值对的hashmapb)安装安装命令-d 选项是启动一个守护进程-m 是分配给Memcache使用的内存数量,单位是MB,默认是64MB-u 是运行Memcache的用户-L 是监听的服务器IP地址,默认应该是本机-I page大小,默认1M-p 是设置Memcache监听的端口,默认是11211,最好是1024以上的端口-c 选项是最大运行的并发连接数,默认是1024,按照你服务器的负载量来设定-P 是设置保存Memcache的pid文件位置-h 打印帮助信息-f 指定chunk增长因子大小,该值越小所能提供的chunk间隔越小,可以减少内存的浪费-n chunk最小尺寸-v 输出警告和错误信息-vv 打印客户端的请求和返回信息PS:Memcached单进程在32位系统中最大使用内存为2G,若在64位系统则没有限制,这是由于32位系统限制单进程最多可使用2G内存,要使用更多内存,可以分多个端口开启多个Memcached进程最大30天的数据过期时间,设置为永久的也会在这个时间过期Key: 最大键长为250字节,大于长度无法存储,常量KEY_MAX_LENGTH 250控制Value: 单个item最大数据是1MB,超过1MB数据不予存储,常量POWER_BLOCK 1048576进行控制运行命令1. 使用telnet连接Memcache服务器端口2. 连接上端口输入stats命令,获取描述Memcache服务器运行情况的参数操作命令 /zzulp/article/details/7823511 命令参数以及用法: 1. s et:命令用于向缓存添加新的键值对。
mybatis中的一二级缓存的实现原理
mybatis中的一二级缓存的实现原理Mybatis是一个优秀的ORM(ObjectRelationalMapping)框架,它提供了一种简单的方式来访问数据库。
在Mybatis中,缓存是一个非常重要的概念,它可以提高应用程序的性能。
Mybatis中的缓存分为一级缓存和二级缓存,下面将详细介绍它们的实现原理。
一级缓存Mybatis中的一级缓存是指在同一个SqlSession中执行相同的SQL语句时,返回的结果会被缓存起来,下一次执行相同的SQL语句时,可以直接从缓存中获取结果,而不需要再次查询数据库。
一级缓存的实现是基于内存的,缓存的生命周期与SqlSession的生命周期一致。
一级缓存是Mybatis默认开启的,可以通过SqlSession的clearCache()方法来清空一级缓存。
二级缓存Mybatis中的二级缓存是指在同一个应用程序中多个SqlSession之间共享缓存数据,它的作用是提高应用程序的性能。
二级缓存的实现是基于缓存机制的,缓存的生命周期与应用程序的生命周期一致。
二级缓存是通过使用单独的缓存空间来实现的,可以使用第三方缓存框架如Ehcache、Redis等来实现。
Mybatis中的二级缓存的使用需要注意以下几点:1. Mapper文件中需要配置开启二级缓存<cacheeviction='LRU'flushInterval='100000'size='1024'readOnly='true'/>2. 对于需要缓存的对象,需要实现Serializable接口3. 在不同的SqlSession中使用同一个Mapper,才能共享缓存数据4. 对于更新、插入、删除操作,会清空相关的缓存总结:Mybatis中的缓存是提高应用程序性能的重要手段,一级缓存和二级缓存的实现原理不同,使用时需要注意它们的区别和限制条件。
Mybatis一级缓存与二级缓存的实现
Mybatis⼀级缓存与⼆级缓存的实现mybatis缓存mybatis作为⼀个流⾏的持久化⼯具,缓存必然是缺少不了的组件。
通过这篇⽂章,就让我们来了解⼀下mybatis的缓存。
mybatis缓存类型说起mybatis的缓存,了解过的同学都知道,mybatis中可以有两种缓存类型:第⼀种,我们通常称为以及缓存,或者sqlSession级别的缓存,这种缓存是mybatis⾃带的,如果mapper中的配置都是默认的话,那么⼀级缓存也是默认开启的。
第⼆种,就是⾮sqlSession级别的缓存了,我们通常称为⼆级缓存,mybatis中的⼆级缓存需要实现Cache接⼝,并且配置在mapper中,要先开启的话,需要⼀些配置,下⾯我们会详细说到。
⼀级缓存作为mybatis⾃带的缓存,我们通过代码来分析⼀下其原理。
⾸先,我们来看下⼀级缓存的效果。
测试代码:@Testpublic void test_Cache() throws Exception {InputStream input = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(input);SqlSession sqlSession = factory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);System.out.println("the first query : ");mapper.queryAllUsers();System.out.println("====================================");System.out.println("the second query : ");mapper.queryAllUsers();mit();}mapper配置如下,我们采⽤默认配置:<select id="queryAllUsers" resultType="User">select * from hwc_users</select>运⾏结果如下:Created connection 1191654595.Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@470734c3]==> Preparing: select * from hwc_users==> Parameters:<== Columns: id, name, age, email<== Row: 1, 胡⽂超, 35, huwenchao@<== Row: 2, 胡⽂超, 35, huwenchao@<== Row: 3, 胡⽂超, 35, huwenchao@<== Row: 4, 胡⽂超, 35, huwenchao@<== Row: 5, 胡⽂超, 35, huwenchao@<== Row: 6, 胡⽂超, 35, huwenchao@<== Row: 7, 胡⽂超, 35, huwenchao@<== Row: 8, 胡⽂超, 35, huwenchao@<== Row: 9, 胡⽂超, 35, huwenchao@<== Total: 9====================================the second query :Cache Hit Ratio [erMapper]: 0.0Process finished with exit code 0从上述结果可以看到,第⼆次查询并没有从数据库获取,并且没有从⼆级缓存中获取,由此可见,默认配置情况下,同⼀个sqlSession中会默认使⽤mybatis的⼀级缓存。
mybatis的缓存机制及用例介绍
mybatis的缓存机制及⽤例介绍在实际的项⽬开发中,通常对数据库的查询性能要求很⾼,⽽mybatis提供了查询缓存来缓存数据,从⽽达到提⾼查询性能的要求。
mybatis的查询缓存分为⼀级缓存和⼆级缓存,⼀级缓存是SqlSession级别的缓存,⼆级缓存时mapper级别的缓存,⼆级缓存是多个SqlSession共享的。
mybatis通过缓存机制减轻数据压⼒,提⾼数据库性能。
⼀级缓存:mybatis的⼀级缓存是SQLSession级别的缓存,在操作数据库时需要构造SqlSession对象,在对象中有⼀个HashMap⽤于存储缓存数据,不同的SqlSession之间缓存数据区域(HashMap)是互相不影响的。
⼀级缓存的作⽤域是SqlSession范围的,当在同⼀个SqlSession中执⾏两次相同的sql语句时,第⼀次执⾏完毕会将数据库中查询的数据写到缓存(内存)中,第⼆次查询时会从缓存中获取数据,不再去底层进⾏数据库查询,从⽽提⾼了查询效率。
需要注意的是:如果SqlSession执⾏了DML操作(insert、update、delete),并执⾏commit()操作,mybatis则会清空SqlSession中的⼀级缓存,这样做的⽬的是为了保证缓存数据中存储的是最新的信息,避免出现脏读现象。
当⼀个SqlSession结束后该SqlSession中的⼀级缓存也就不存在了,Mybatis默认开启⼀级缓存,不需要进⾏任何配置。
注意:Mybatis的缓存机制是基于id进⾏缓存,也就是说Mybatis在使⽤HashMap缓存数据时,是使⽤对象的id作为key,⽽对象作为value保存例⼦说明:⼯程架构图:pom.xml<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance" xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion><groupId>com.gm.test</groupId><artifactId>MybatisCacheTest</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- spring版本号 --><spring.version>4.3.10.RELEASE</spring.version><!-- mybatis版本号 --><mybatis.version>3.2.6</mybatis.version><!-- log4j⽇志⽂件管理包版本 --><slf4j.version>1.7.7</slf4j.version><log4j.version>1.2.17</log4j.version></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><!-- 表⽰开发的时候引⼊,发布的时候不会加载此包 --><scope>test</scope></dependency><!-- spring核⼼包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-oxm</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency><!-- aop --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.4</version></dependency><!-- mybatis核⼼包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><!-- mybatis/spring包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.2.2</version></dependency><!-- 导⼊java ee jar 包 --><dependency><groupId>javax</groupId><artifactId>javaee-api</artifactId><version>7.0</version></dependency><!-- 导⼊Mysql数据库链接jar包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.30</version></dependency><!-- 导⼊dbcp的jar包,⽤来在applicationContext.xml中配置数据库 --> <dependency><groupId>commons-dbcp</groupId><artifactId>commons-dbcp</artifactId><version>1.2.2</version></dependency><!-- JSTL标签类 --><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!-- ⽇志⽂件管理包 --><!-- log start --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><!-- 格式化对象,⽅便输出⽇志 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.1.41</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>${slf4j.version}</version></dependency><!-- log end --></dependencies><build><plugins><plugin><artifactId>maven-war-plugin</artifactId><configuration><version>3.1</version></configuration></plugin></plugins></build></project>sql语句:CREATE TABLE employee(id INT(11) PRIMARY KEY AUTO_INCREMENT,loginname VARCHAR(18),PASSWORD VARCHAR(18),NAME VARCHAR(18) DEFAULT NULL,sex CHAR(2) DEFAULT NULL,age INT(11) DEFAULT NULL,phone VARCHAR(21),sal DOUBLE,state VARCHAR(18));INSERT INTO employee (loginname,PASSWORD,NAME,sex,age,phone,sal,state) VALUES('jack','123456','杰克','男',26,'12345678936',9800,'ACTIVE'); INSERT INTO employee (loginname,PASSWORD,NAME,sex,age,phone,sal,state) VALUES('rose','123456','露丝','⼥',21,'78965412395',6800,'ACTIVE'); INSERT INTO employee (loginname,PASSWORD,NAME,sex,age,phone,sal,state) VALUES('tom','123456','汤姆','男',25,'139********',8800,'ACTIVE'); INSERT INTO employee (loginname,PASSWORD,NAME,sex,age,phone,sal,state) VALUES('alice','123456','爱丽丝','⼥',20,'74185296375',5800,'ACTIVE'); log4j.properties:log4j.rootLogger=ERROR, stdout.gm.mapper.EmployeeMapper=DEBUGlog4j.appender.console=org.apache.log4j.ConsoleAppenderyout=org.apache.log4j.PatternLayoutyout.ConversionPattern=[%-12d{HH\:mm\:ss.SS}] [%p] %l %m%nlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderyout=org.apache.log4j.PatternLayoutyout.ConversionPattern=%d %p [%c] - %m%nmybatis-config.xml:<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration PUBLIC "-////DTD Config 3.0//EN" "/dtd/mybatis-3-config.dtd"><configuration><!-- 全局参数 --><settings><!-- 设置但JDBC类型为空时,某些驱动程序要指定值,default:OTHER,插⼊空值时不需要指定类型 --><setting name="jdbcTypeForNull" value="NULL" /><!-- 要使延迟加载⽣效必须配置下⾯两个属性 --><setting name="lazyLoadingEnabled" value="true" /><setting name="aggressiveLazyLoading" value="false" /><setting name="logImpl" value="LOG4J" /></settings><!-- <plugins> <plugin interceptor="com.manager.util.MybatisInterceptor"></plugin></plugins> --><environments default="mysql"><environment id="mysql"><!-- 指定事务管理类型,type="JDBC"指直接简单使⽤了JDBC的提交和回滚设置 --><transactionManager type="JDBC" /><!-- dataSource指数据源配置,POOLED是JDBC连接对象的数据源连接池的实现 --><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis" /><property name="username" value="root" /><property name="password" value="1qaz@wsx" /></dataSource></environment></environments><mappers><mapper resource="com/gm/mapper/EmployeeMapper.xml" /></mappers></configuration>Employee.java:package com.gm.domain;import java.io.Serializable;public class Employee implements Serializable {/****/private static final long serialVersionUID = 1L;private Integer id;private String loginname;private String password;private String name;private String sex;private String age;private String phone;private Double sal;private String state;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getLoginname() {return loginname;}public void setLoginname(String loginname) {this.loginname = loginname;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getName() {return name;}public void setName(String name) { = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public Double getSal() {return sal;}public void setSal(Double sal) {this.sal = sal;}public String getState() {return state;}public void setState(String state) {this.state = state;}}EmployeeMapper.xml:<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN" "/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.gm.mapper.EmployeeMapper"><select id="selectEmployeeById" parameterType="int"resultType="com.gm.domain.Employee">SELECT * FROM employee WHERE id = #{id}</select><!-- 查询所有Employee --><select id="selectAllEmployee" parameterType="int"resultType="com.gm.domain.Employee">SELECT * FROM employee</select><!-- 根据id删除Employee --><delete id="deleteEmployeeById" parameterType="int">DELETE FROMemployee WHERE id = #{id}</delete></mapper>EmployeeMapper.java:package com.gm.mapper;import java.util.List;import com.gm.domain.Employee;public interface EmployeeMapper {// 根据id查询EmployeeEmployee selectEmployeeById(Integer id);// 查询所有EmployeeList<Employee> selectAllEmployee();// 根据id删除Employeevoid deleteEmployeeById(Integer id);}⼯⼚⼯具类:MySqlSessionFactory.java:package com.gm.factory;import java.io.IOException;import java.io.InputStream;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;public class MySqlSessionFactory {private static SqlSessionFactory sqlSessionFactory = null;static {try {InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}// 获取SqlSession对象的静态⽅法public static SqlSession getSqlSession() {return sqlSessionFactory.openSession();}// 获取SqlSessionFactory的静态⽅法public static SqlSessionFactory getSessionFactory() {return sqlSessionFactory;}}执⾏⽅法类⼀:OneLevelCacheTest.javapackage com.gm.test;import org.apache.ibatis.session.SqlSession;import com.gm.domain.Employee;import com.gm.factory.MySqlSessionFactory;import com.gm.mapper.EmployeeMapper;public class OneLevelCacheTest {public void testCache1() {// 使⽤⼯⼚类获得SqlSession对象SqlSession sqlSession = MySqlSessionFactory.getSqlSession();// 获得EmployeeMapping对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee1 = employeeMapper.selectEmployeeById(1);System.out.println(employee1);// 再次查询id为1的Employee对象,因为是同⼀个SqlSession,所以会从之前的⼀级缓存中查找数据Employee employee2 = employeeMapper.selectEmployeeById(1);System.out.println(employee2);sqlSession.close();}public static void main(String[] args) {OneLevelCacheTest t = new OneLevelCacheTest();t.testCache1();}public void testCache2() {// 使⽤⼯⼚类获得SqlSession对象SqlSession sqlSession = MySqlSessionFactory.getSqlSession();// 获得EmployeeMapping对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee1 = employeeMapper.selectEmployeeById(1);System.out.println(employee1);// 执⾏delete操作employeeMapper.deleteEmployeeById(4);// commit提交mit();// 再次查询id为1的Employee对象,因为DML操作会清空sqlSession缓存,所以会再次执⾏select语句Employee employee2 = employeeMapper.selectEmployeeById(1);System.out.println(employee2);sqlSession.close();}public void testCache3() {// 使⽤⼯⼚类获得SqlSession对象SqlSession sqlSession = MySqlSessionFactory.getSqlSession();// 获得EmployeeMapping对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee1 = employeeMapper.selectEmployeeById(1);System.out.println(employee1);// 关闭⼀级缓存sqlSession.close();// 再次访问,需要再次获取⼀级缓存,然后才能查找数据,否则会抛出异常sqlSession = MySqlSessionFactory.getSqlSession();// 再次获得EmployeeMapper对象employeeMapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee2 = employeeMapper.selectEmployeeById(1);System.out.println(employee2);sqlSession.close();}public void testCache4() {// 使⽤⼯⼚类获得SqlSession对象SqlSession sqlSession = MySqlSessionFactory.getSqlSession();// 获得EmployeeMapping对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee1 = employeeMapper.selectEmployeeById(1);System.out.println(employee1);// 关闭⼀级缓存sqlSession.close();// 再次访问,需要再次获取⼀级缓存,然后才能查找数据,否则会抛出异常sqlSession = MySqlSessionFactory.getSqlSession();// 再次获得EmployeeMapper对象employeeMapper = sqlSession.getMapper(EmployeeMapper.class);// 再次查询id为1的Employee对象,因为DML操作会清空sqlSession缓存,所以会再次执⾏select语句Employee employee2 = employeeMapper.selectEmployeeById(1);System.out.println(employee2);sqlSession.close();}}运⾏之后结果:2018-08-22 09:35:47,858 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ? 2018-08-22 09:35:47,886 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)2018-08-22 09:35:47,899 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1com.gm.domain.Employee@56235b8ecom.gm.domain.Employee@56235b8e通过观察结果可以看出,在第⼀次查询id为1的Employee对象时执⾏了⼀条select语句,但是第⼆次获取id为1的Employee对象时并没有执⾏select语句,因为此时⼀级缓存也就是SqlSession缓存中已经缓存了id为1的Employee对象,Mybatis直接从缓存中将对象取出来,并没有再次去查询数据库,所以第⼆次也就没有执⾏select语句执⾏⽅法类⼆:public static void main(String[] args) {OneLevelCacheTest t = new OneLevelCacheTest();t.testCache2();}运⾏之后的结果:2018-08-22 09:41:17,024 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?2018-08-22 09:41:17,045 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)2018-08-22 09:41:17,058 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1com.gm.domain.Employee@56235b8e2018-08-22 09:41:17,058 DEBUG [com.gm.mapper.EmployeeMapper.deleteEmployeeById] - ==> Preparing: DELETE FROM employee WHERE id = ?2018-08-22 09:41:17,059 DEBUG [com.gm.mapper.EmployeeMapper.deleteEmployeeById] - ==> Parameters: 4(Integer)2018-08-22 09:41:17,079 DEBUG [com.gm.mapper.EmployeeMapper.deleteEmployeeById] - <== Updates: 12018-08-22 09:41:17,125 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?2018-08-22 09:41:17,125 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)2018-08-22 09:41:17,128 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1com.gm.domain.Employee@370736d9结果分析:在第⼀次查询id为1的employee对象时执⾏了⼀条select语句,接下来执⾏了⼀个delete并commit操作,Mybatis为了保证缓存中存储的是最新消息,会清空SqlSession缓存。
mybatis缓存总结
mybatis缓存总结⼀、什么是mybatis缓存,怎么使⽤mybatis缓存分为⼀级缓存和⼆级缓存,缓存就是将从数据库中查询到的数据放⼊到临时缓冲区内存中;⼀级缓存是⼀直开启的;SqlSession级别的⼀个Map与数据库同⼀次会话期间查询到的数据会放在本地缓存中,再次查询时如果获取相同的数据,直接从缓存中拿,不在从数据库查询。
⼆、⼀级缓存失效的情况1、sqlsession不同,2 sqlsession相同,查询条件不同(缓存中没有这个数据)3、sqlsession相同,两次查询之间执⾏了增删改操作4、sqlsession相同⼿动清除了⼀级缓存三、⼆级缓存的⼯作机制以及使⽤⼆级缓存(全局缓存):基于namespace级别的缓存:⼀个namespace对应⼀个⼆级缓存;⼯作机制: 1、⼀个会话,查询⼀条数据,这个数据就会被放在当前会话的⼀级缓存中;2、如果会话关闭;⼀级缓存中的数据会被保存到⼆级缓存中;新的会话查询信息,就可以参照⼆级缓存中的内容;不同namespace查出的数据会放在⾃⼰对应的缓存中(map) 效果:数据会从⼆级缓存中获取查出的数据都会被默认先放在⼀级缓存中。
只有会话提交或者关闭以后,⼀级缓存中的数据才会转移到⼆级缓存中3、使⽤:1)POJO需要实现序列化接⼝ 2)去mapper.xml中配置使⽤⼆级缓存 <cache></cache> 3)开启全局⼆级缓存配置:<setting name="cacheEnabled" value="true"/>四、缓存有关的设置、属性1)、cacheEnabled=true:false:关闭缓存(⼆级缓存关闭)(⼀级缓存⼀直可⽤的)2)、每个select标签都有useCache="true": false:不使⽤缓存(⼀级缓存依然使⽤,⼆级缓存不使⽤)3)、【每个增删改标签的:flushCache="true":(⼀级⼆级都会清除)】增删改执⾏完成后就会清楚缓存;测试:flushCache="true":⼀级缓存就清空了;⼆级也会被清除;如果flushCache=true;每次查询之后都会清空缓存;缓存是没有被使⽤的;4)、sqlSession.clearCache();只是清楚当前session的⼀级缓存;5)、localCacheScope:本地缓存作⽤域:(⼀级缓存SESSION);当前会话的所有数据保存在会话缓存中;STATEMENT:可以禁⽤⼀级缓存;第三⽅缓存整合:1)、导⼊第三⽅缓存2)、导⼊与第三⽅缓存整合的适配包;官⽅有;包即可;3)、mapper.xml中使⽤⾃定义缓存<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>@Testpublic void testSecondLevelCache02() throws IOException{SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();SqlSession openSession = sqlSessionFactory.openSession();SqlSession openSession2 = sqlSessionFactory.openSession();try{//1、DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);DepartmentMapper mapper2 = openSession2.getMapper(DepartmentMapper.class);Department deptById = mapper.getDeptById(1);System.out.println(deptById);openSession.close();Department deptById2 = mapper2.getDeptById(1);System.out.println(deptById2);openSession2.close();//第⼆次查询是从⼆级缓存中拿到的数据,并没有发送新的sql}finally{}}@Testpublic void testSecondLevelCache() throws IOException{SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();SqlSession openSession = sqlSessionFactory.openSession();SqlSession openSession2 = sqlSessionFactory.openSession();try{//1、EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);Employee emp01 = mapper.getEmpById(1);System.out.println(emp01);openSession.close();//第⼆次查询是从⼆级缓存中拿到的数据,并没有发送新的sql//mapper2.addEmp(new Employee(null, "aaa", "nnn", "0"));Employee emp02 = mapper2.getEmpById(1);System.out.println(emp02);openSession2.close();}finally{}}@Testpublic void testFirstLevelCache() throws IOException{SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();SqlSession openSession = sqlSessionFactory.openSession();try{EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);Employee emp01 = mapper.getEmpById(1);System.out.println(emp01);//xxxxx//1、sqlSession不同。
mybatis原理-mybatis的一级缓存详解和注意事项_文章_DevStore
前言
MyBatis是一个简单、小巧功能非常强大的ORM开源框架,它的强大在缓存机制上展示的淋淋尽致。MyBatis提 供了一级缓存、二级缓存 这两个缓存机制,能够很好地处理和维护缓存,提高系统的性能。本文详细介绍 MyBatis的一级缓存,深入源码,解析MyBatis一级缓存实现原理,并且针对一级缓存的特点提出了在实际使用过 程中应该注意的事项。
由于Session级别的一级缓存实际上就是使用 怎样实现的呢?
PerpetualCache维护的,那么PerpetualCache是
PerpetualCache实现原理其实很简单,其内部就是通过一个简单的HashMap<k,v> 来实现的, 没有其他的任何限制。如下是PerpetualCache的实现代码:
rowBounds.offset和rowBounds.limit来过滤查询出来的结果集,这种分页功能是基 于查询结果的再过滤,而不是进行数据库的物理分页; 由于
MyBatis底层还是依赖于JDBC实现的,那么,对于两次完全一模一样的查询, MyBatis要保证对于底层JDBC而言,也是完全一致的查询才行。而对于JDBC而言,两
8. import org.apache.ibatis.cache.CacheException; 9. 10. /** 11. * 使用简单的HashMap来维护缓存 12. * @author Clinton Begin 13. */ 14. public class PerpetualCache implements Cache { 15. 16. private String id; 17. 18. private Map<Object, Object> cache = new HashMap<Object, 19. 20. public PerpetualCache(String id) { 21. this.id = id; 22. } 23. 24. public String getId() { 25. return id; 26. } 27. 28. public int getSize() { 29. return cache.size(); 30. } 31. 32. public void putObject(Object key, Object value) { 33. cache.put(key, value); 34. } 35. 36. public Object getObject(Object key) { 37. return cache.get(key); 38. } 39. 40. public Object removeObject(Object key) { 41. return cache.remove(key); 42. } 43. 44. public void clear() { 45. cache.clear(); 46.
mybatis缓存原理
mybatis缓存原理介绍mybatis是一款开源的持久层框架,可以将数据库操作与Java代码进行解耦。
在使用mybatis进行数据库操作时,会涉及到缓存的使用,而mybatis的缓存机制对于提高系统性能至关重要。
本文将深入探讨mybatis的缓存原理,包括缓存的分类、缓存的生命周期、缓存的清除机制以及如何配置和使用mybatis的缓存。
缓存分类mybatis的缓存机制主要分为一级缓存和二级缓存。
一级缓存也称为本地缓存,它位于SqlSession对象内部,一级缓存的作用域是SqlSession。
二级缓存位于mapper映射文件的命名空间内,作用域是一个SqlSessionFactory。
一级缓存是默认开启的,而二级缓存需要手动配置才会生效。
一级缓存原理1.当SqlSession执行查询时,查询结果会同时存储在一级缓存中。
2.下次查询相同的数据,会先从一级缓存中查询,如果存在则直接返回缓存中的数据,不再执行数据库查询操作。
3.一级缓存的生命周期是SqlSession的生命周期,即每次打开一个新的SqlSession,就会创建一个新的一级缓存。
二级缓存原理1.当SqlSession执行查询时,查询结果会同时存储在二级缓存中。
2.下次查询相同的数据,会先从二级缓存中查询,如果存在则直接返回缓存中的数据,不再执行数据库查询操作。
3.二级缓存的生命周期是一个SqlSessionFactory,它是一个全局的缓存,多个SqlSession共享同一个二级缓存。
4.当有更新操作(增、删、改)时,会清空二级缓存,保证数据的一致性。
缓存的清除机制mybatis提供了多种方式来清除缓存,可以根据具体的业务需求来选择合适的清除方式。
1. 手动清除缓存:可以调用SqlSession的clearCache方法来清除一级缓存。
2. 配置缓存策略:可以在映射文件中配置flushCache属性来控制是否清除缓存。
当flushCache属性设置为true时,每次执行更新操作都会清除缓存,默认为true。
mybatis一级缓存和二级缓存原理
mybatis一级缓存和二级缓存原理
MyBatis一级缓存和二级缓存是MyBatis框架提供的两种缓存机制,用于提高数据读取性能。
一级缓存是指在MyBatis中SqlSession级别的缓存,它是默认开启的。
当SqlSession执行某个查询语句时,查询结果会被缓存到一级缓存中。
当再次执行同样的查询语句时,MyBatis会先从一级缓存中查找结果,如果存在,则直接返回缓存中的结果,否则再去数据库中查询。
一级缓存的生命周期与SqlSession的生命周期一致,只有在SqlSession关闭或清空缓存时才会失效。
二级缓存是指在MyBatis中全局范围的缓存,它是需要手动配置的。
当SqlSession执行某个查询语句时,查询结果会被缓存到二级缓存中。
当再次执行同样的查询语句时,MyBatis会先从二级缓存中查找结果,如果存在,则直接返回缓存中的结果,否则再去数据库中查询。
二级缓存的生命周期与应用程序的生命周期一致,只要应用程序没有关闭,二级缓存就会一直存在。
需要注意的是,一级缓存和二级缓存并不是完全相同的机制。
一级缓存是在SqlSession级别的缓存,而二级缓存是在全局范围的缓存。
一级缓存是默认开启的,而二级缓存需要手动配置。
另外,一级缓存只能用于同一个SqlSession中的查询,而二级缓存可以跨SqlSession共享缓存。
不过,由于二级缓存是全局缓存,所以需要考虑并发访问的问题,仅在数据更新不频繁且数据量较小的情况下才适用。
mybatis 缓存原理
mybatis 缓存原理MyBatis 缓存原理MyBatis 是一个优秀的持久层框架,它提供了强大的SQL 映射功能,让开发者能够更加方便地与数据库交互。
其中一个重要的特性就是缓存机制,它可以大幅度提高查询性能,减少数据库的压力。
MyBatis 的缓存机制分为一级缓存和二级缓存两个层次。
一级缓存是指在同一个SqlSession 中,多次执行相同SQL 语句时,MyBatis 会将查询结果缓存起来,下次再执行相同的SQL 语句时,直接从缓存中获取结果,而不需要再去查询数据库。
这种缓存是默认开启的,可以通过配置文件进行关闭。
二级缓存是指在多个SqlSession 中,多次执行相同SQL 语句时,MyBatis 会将查询结果缓存到一个共享的缓存区域中,下次再执行相同的SQL 语句时,可以直接从缓存中获取结果,而不需要再去查询数据库。
二级缓存需要手动开启,并且需要在映射文件中配置缓存的作用域,可以选择是在同一个命名空间中共享缓存,还是在全局共享缓存。
MyBatis 的缓存机制基于事务和时间戳实现,当一个SQL 语句执行后,MyBatis 会记录该SQL 语句的事务和时间戳,将查询结果和事务和时间戳一同缓存起来。
当下次执行相同的 SQL 语句时,MyBatis 会检查缓存中的事务和时间戳是否和当前的事务和时间戳一致,如果一致,则直接从缓存中获取结果,否则重新查询数据库。
缓存的失效是由于数据的更新造成的,MyBatis 会通过拦截器来捕捉到数据的更新操作,并将缓存中相关的数据进行失效处理。
此外,MyBatis 还提供了手动清除缓存的方法,可以通过调用 SqlSession 的clearCache 方法来清除缓存。
总的来说,MyBatis 的缓存机制可以显著提高查询性能,减少数据库的压力。
开发者可以根据实际需求选择是否开启缓存,并合理配置缓存的作用域和清除策略,以达到最佳的性能和数据一致性。
同时,开发者需要注意缓存的失效机制,确保缓存数据的准确性和及时性。
Mybatis的缓存机制
Mybatis的缓存机制为什么要使⽤缓存?在计算机的世界⾥⾯缓存⽆处不在,操作系统有操作系统的缓存、数据库有数据库的缓存,各种中间件如Redis也⽤来充当缓存的作⽤,编程语⾔⼜利⽤内存作为缓存。
计算机CPU的处理速度可谓是⼀马当先,远远甩开了其他操作,尤其是I/O操作,除了那种CPU密集型的系统,其余⼤部分的业务系统性能瓶颈最后或多或少都会出现在I/O操作上,所以为了减少磁盘的I/O次数,那么缓存是必不可少的,通过缓存的使⽤我们可以⼤⼤减少I/O操作次数,从⽽在⼀定程度上弥补了I/O操作和CPU处理速度之间的鸿沟。
⽽在我们ORM框架中引⼊缓存的⽬的就是为了减少读取数据库的次数,从⽽提升查询的效率。
那mybatis作为⼀款优秀的ORM框架,也不会少了缓存机制,那作为框架的使⽤者,我们有必要了解⼀下mybatis的缓存是如何实现的。
mybatis的缓存mybatis的缓存相关类都在cache包⾥⾯,在包⾥定义了⼀个顶级接⼝Cache,这个接⼝默认有⼀个实现类PerpetualCache,⽽PerpetualCache中是维护了⼀个HashMap来实现缓存。
这⾥需要注意的是,虽然decorators包下的类也实现了Cache接⼝,那为什么还要说Cache接⼝只有⼀个默认实现类呢?其实从包名decorator就可以得知,这个包⾥的类全都是装饰器,也就是说这是装饰器模式的实现。
随意打开⼀个装饰器,可以最终都是调⽤delegate来实现,只是将部分功能做了增强,其本⾝都需要依赖Cache的唯⼀实现类PerpetualCache(因为装饰器内需要传⼊Cache对象,故⽽只能传⼊PerpetualCache对象,因为接⼝是⽆法直接new出来传进去的)。
在mybatis中,缓存分为⼀级缓存和⼆级缓存⼀级缓存⼀级缓存也叫本地缓存,在mybatis中,⼀级缓存是在会话(sqlSession)层⾯实现的,这也表明⼀级缓存只能在同⼀个会话中有效,跨sqlSession是⽆效的。
Mybatis的一级缓存和二级缓存的理解以及用法
Mybatis的⼀级缓存和⼆级缓存的理解以及⽤法 程序中为什么使⽤缓存? 先了解⼀下缓存的概念:原始意义是指访问速度⽐⼀般随机存取存储器快的⼀种RAM,通常它不像系统主存那样使⽤DRAM技术,⽽使⽤昂贵但较快速的SRAM技术。
对于我们编程来说,所谓的缓存,就是将程序或系统经常要调⽤的对象(临时数据)存在内存中,⼀遍其使⽤时可以快速调⽤,不必再去创建新的重复的实例。
这样做可以减少系统的开销,提⾼效率。
对缓存有了⼀定的了解以后就知道了使⽤缓存是为了减少和数据库的交互次数,提⾼执⾏效率。
那么下⼀个问题来了。
什么样的数据能使⽤缓存,什么样的数据不能使⽤? 这是我们使⽤缓存必须要明确的事情,实际上适⽤于缓存的数据:经常查询并且不经常改变的,并且的数据的正确与否对最终结果影响不⼤的、不适⽤于缓存的数据:经常改变的数据,数据的正确与否对最终结果影响很⼤的。
Mybatis中的⼀级缓存和⼆级缓存到底缓存了什么,缓存了以后⼜有什么效果,缓存的数据什么时候会被清空? ⼀级缓存:它指的是Mybatis中sqlSession对象的缓存,当我们执⾏查询以后,查询的结果会同时存⼊到SqlSession为我们提供的⼀块区域中,该区域的结构是⼀个Map,当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,的话直接拿出来⽤,当SqlSession对象消失时,mybatis的⼀级缓存也就消失了,同时⼀级缓存是SqlSession范围的缓存,当调⽤SqlSession的修改、添加、删除、commit(),close等⽅法时,就会清空⼀级缓存。
⼆级缓存:他值得是Mybatis中SqlSessionFactory对象的缓存,由同⼀个SqlSessionFactory对象创建的SqlSession共享其缓存,但是其中缓存的是数据⽽不是对象,所以从⼆级缓存再次查询出得结果的对象与第⼀次存⼊的对象是不⼀样的。
通过简单的例⼦来加深理解⼀级缓存和⼆级缓存。
mybatis中的一二级缓存的实现原理
mybatis中的一二级缓存的实现原理
Mybatis是一款非常流行的Java持久层框架,它采用了缓存机制来提高数据库交互的效率。
其中一级缓存和二级缓存是两种不同的缓存机制,它们都有自己的实现原理。
一级缓存是指在同一个SqlSession中执行相同的SQL语句,返回的结果会被缓存起来。
在同一个SqlSession中,如果执行了相同的SQL语句,Mybatis会先从缓存中查找结果,如果有则直接返回,如果没有则执行SQL语句并将结果缓存。
一级缓存的实现原理是通过一个HashMap来存储结果,其中key为SQL语句,value为结果集。
二级缓存是指在同一个Mapper中执行相同的SQL语句,返回的结果会被缓存起来。
二级缓存是跨SqlSession的,也就是说在不同的SqlSession中执行相同的SQL语句,返回的结果会先从二级缓存中查找。
二级缓存的实现原理是通过一个Cache接口来实现的,该接口有多种实现方式,比如Ehcache、Redis等。
其中,Mybatis默认使用PerpetualCache作为二级缓存的实现方式。
需要注意的是,一级缓存和二级缓存并不是完全相同的,它们有不同的适用场景。
一级缓存适用于单条数据查询,而二级缓存适用于多条数据查询。
此外,在使用二级缓存时需要注意缓存的有效期,避免出现脏数据问题。
总之, Mybatis的缓存机制是通过一级缓存和二级缓存来提高数据库交互效率的。
对于开发者来说,需要根据业务需求选择合适的缓存机制,避免出现性能问题。
mybatis缓存机制的理解
MyBatis 是一款流行的 Java 持久层框架,在处理数据库操作时具有高效性和灵活性。
为了提升查询性能,MyBatis 提供了缓存机制,可以将查询结果缓存起来并复用,减少对数据库的访问次数,从而提高系统的响应速度。
本文将介绍 MyBatis 缓存机制的原理和使用方法。
一、MyBatis 缓存机制的原理MyBatis 缓存机制是基于对象的缓存,它将查询结果缓存在内存中,以避免重复查询数据库。
MyBatis 的缓存机制主要由以下几部分组成:一级缓存、二级缓存和本地缓存。
1. 一级缓存:一级缓存是指在同一个 SqlSession 中,对于相同的查询语句和参数,MyBatis 会将查询结果缓存在内存中。
这样,如果后续再次执行相同的查询,MyBatis 会直接从缓存中获取结果,而不需要再次查询数据库。
一级缓存的生命周期与 SqlSession 相同,当 SqlSession 调用 commit()、close()、clearCache() 等方法时,一级缓存会被清空。
此外,如果在同一个SqlSession 中进行了更新、插入或删除操作,可能会导致一级缓存失效,即查询结果不会被缓存。
2. 二级缓存:二级缓存是指在不同的 SqlSession 之间共享缓存。
当多个 SqlSession 执行相同的查询,并且开启了二级缓存配置,MyBatis 会将查询结果缓存在二级缓存中。
这样,其他SqlSession 执行相同的查询时,可以直接从二级缓存中获取结果,而无需再次查询数据库。
二级缓存的作用域是 Mapper 级别的,即同一个 Mapper 接口中的方法共享缓存。
要启用二级缓存,需要在配置文件中配置<cache /> 标签,并在Mapper 接口中添加@CacheNamespace 注解。
3. 本地缓存:本地缓存是指 MyBatis 在执行查询时,会将查询结果缓存在 Statement 对象中。
如果后续再次执行相同的查询,MyBatis 会直接从 Statement 对象中获取结果,而无需再次查询数据库。
MyBatis经典面试题及答案
MyBatis经典⾯试题及答案1、什么是MyBatis?答:MyBatis是⼀个可以⾃定义SQL、存储过程和⾼级映射的持久层框架。
2、讲下MyBatis的缓存答:MyBatis的缓存分为⼀级缓存和⼆级缓存,⼀级缓存放在session⾥⾯,默认就有,⼆级缓存放在它的命名空间⾥,默认是不打开的,使⽤⼆级缓存属性类需要实现Serializable序列化接⼝(可⽤来保存对象的状态),可在它的映射⽂件中配置<cache/>1、⼀级缓存的⽣命周期有多长?a、MyBatis在开启⼀个数据库会话时,会创建⼀个新的SqlSession对象,SqlSession对象中会有⼀个新的Executor对象。
Executor对象中持有⼀个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也⼀并释放掉。
b、如果SqlSession调⽤了close()⽅法,会释放掉⼀级缓存PerpetualCache对象,⼀级缓存将不可⽤。
c、如果SqlSession调⽤了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使⽤。
d、SqlSession中执⾏了任何⼀个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使⽤2、怎么判断某两次查询是完全相同的查询?mybatis认为,对于两次查询,如果以下条件都完全⼀样,那么就认为它们是完全相同的两次查询。
2.1 传⼊的statementId2.2 查询时要求的结果集中的结果范围2.3. 这次查询所产⽣的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() )2.4 传递给java.sql.Statement要设置的参数值如果我们配置了⼆级缓存就意味着:映射语句⽂件中的所有select语句将会被缓存。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和
mybatis整合ehcache
1 查询缓存1.1 什么是查询缓存mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybaits 提供一级缓存,和二级缓存。
一级缓存是SqlSession级别的缓存。
在操作数据库时需要构造sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。
不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。
当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。
Mybatis默认开启一级缓存。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper 的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
二级缓存是多个SqlSession 共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql 中传递参数也相同即最终执行相同的sql语句,第一次执行
完毕会将数据库中查询的数据写到缓存(内存),第二次会
从缓存中获取数据将不再从数据库查询,从而提高查询效率。
Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。
如果缓存中有数据就不用从数据库中获取,大大提高系统性能。
1.2 一级缓存1.2.1 一级缓存工作原理下图是根据id查询用户的一级缓存图解第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的
用户信息,如果没有,从数据库查询用户信息。
得到用户信息,将用户信息存储到一级缓存中。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
1.2.2 一级缓存测试mybatis默认支持一级缓存,不需要在配置文件去配置。
按照上边一级
缓存原理步骤去测试。
@Test public void testCache1() throws Exception{ SqlSessionsqlSession = sqlSessionFactory.openSession();//创建代理对象UserMapperuserMapper =
sqlSession.getMapper(UserMapper.class); //
下边查询使用一个SqlSession //第一次发起请求,查询id为1的用户Useruser1 =
userMapper.findUserById(1);
System.out.println(user1); // 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
//更新user1的信息
user1.setUsername('测试用户22');
userMapper.updateUser(user1); //执行commit操作去清空缓存mit(); //第二次发起请求,查询id为1的用户Useruser2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close(); }1.2.3 一级缓存应用正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括很多mapper方法调用。
service{ //开始执行时,开启事务,创建SqlSession 对象//第一次调用mapper的方法findUserById(1) //第二次调用mapper的方法findUserById(1),从一级缓存中取数据//aop控制只要方法结束,sqlSession 关闭sqlsession关闭后就销毁数据结构,清空缓存Service结束sqlsession关闭}如果是执行两次service调用查询相同的用户信息,不走一级缓存,因为Service方法结束,sqlSession就关闭,一级缓存就清空。
1.3 二级缓存
1.3.1 原理首先开启mybatis的二级缓存。
sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。
如果SqlSession3去执行相同mapper下sql,执行commit提交,清空该mapper下的二级缓存区域的数据。
sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
数据类型仍然为HashMapUserMapper有一个二级缓存区域(按namespace分,如果namespace相同则使用同一个相同的二级缓存区),其它mapper也有自己的二级缓存区域(按namespace分)。
每一个namespace的mapper 都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。
1.3.2 开启二级缓存mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。
在核心配置文件SqlMapConfig.xml中加入
<settingname='cacheEnabled'value='true'/><!-- 全局配置参数,需要时再设置--> <settings>
<!-- 开启二级缓存默认值为true -->
<settingname='cacheEnabled'value='true'/>
</settings> 描述允许值默认值cacheEnabled对在此配置文件下的所有cache 进行全局性开/关设置。
true falsetrue。