MyBatis缓存分为一级缓存和二级缓存
一级缓存
MyBatis的一级缓存指的是在一个Session域内,session为关闭的时候执行的查询会根据SQL为key被缓存(跟mysql缓存一样,修改任何参数的值都会导致缓存失效)
1)单独使用MyBatis而不继承Spring,使用原生的MyBatis的SqlSessionFactory来构造sqlSession查询,是可以使用以及缓存的,示例代码如下
public class Test { public static void main(String[] args) throws IOException { String config = "mybatis-config.xml"; InputStream is = Resources.getResourceAsStream(config); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); SqlSession session = factory.openSession(); System.out.println(session.selectOne("selectUserByID", 1)); // 同一个session的相同sql查询,将会使用一级缓存 System.out.println(session.selectOne("selectUserByID", 1)); // 参数改变,需要重新查询 System.out.println(session.selectOne("selectUserByID", 2)); // 清空缓存后需要重新查询 session.clearCache(); System.out.println(session.selectOne("selectUserByID", 1)); // session close以后,仍然使用同一个db connection session.close(); session = factory.openSession(); System.out.println(session.selectOne("selectUserByID", 1)); } }
输出如下
DEBUG - Openning JDBC Connection
DEBUG - Created connection 10044878.
DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
DEBUG - ==> Parameters: 1(Integer)
1|test1|19|beijing
1|test1|19|beijing
DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
DEBUG - ==> Parameters: 2(Integer)
2|test2|18|guangzhou
DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
DEBUG - ==> Parameters: 1(Integer)
1|test1|19|beijing
DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - Returned connection 10044878 to pool.
DEBUG - Openning JDBC Connection
DEBUG - Checked out connection 10044878 from pool.
DEBUG - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@9945ce]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
DEBUG - ==> Parameters: 1(Integer)
1|test1|19|beijing
看以看出来,当参数不变的时候只进行了一次查询,参数变更以后,则需要重新进行查询,而清空缓存以后,参数相同的查询过的SQL也需要重新查询,而且使用的数据库连接是同一个数据库连接,这里要得益于我们在mybatis-config.xml里面的datasource设置
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"> </transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments>
注意datasource使用的是POOLED,也就是使用了连接池,所以数据库连接可回收利用,当然这个environment属性在集成spring的时候是不需要的,因为我们需要另外配置datasource的bean.
2) 跟Spring集成的时候(使用mybatis-spring)
直接在dao里查询两次同样参数的sql
@Repository public class UserDao extends SqlSessionDaoSupport { public User selectUserById(int id) { SqlSession session = getSqlSession(); session.selectOne("dao.userdao.selectUserByID", id); // 由于session的实现是SqlSessionTemplate的动态代理实现 // 它已经在代理类内执行了session.close(),所以无需手动关闭session return session.selectOne("dao.userdao.selectUserByID", id); } }
观察日志
DEBUG - Creating a new SqlSession
DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e389b8] was not registered for synchronization because synchronization is not active
DEBUG - Fetching JDBC Connection from DataSource
DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e389b8]
DEBUG - Returning JDBC Connection to DataSource
DEBUG - Creating a new SqlSession
DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@169da74] was not registered for synchronization because synchronization is not active
DEBUG - Fetching JDBC Connection from DataSource
DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@169da74]
DEBUG - Returning JDBC Connection to DataSource
这里执行了2次sql查询,看似我们使用了同一个sqlSession,但是实际上因为我们的dao继承了SqlSessionDaoSupport,而SqlSessionDaoSupport内部sqlSession的实现是使用用动态代理实现的,这个动态代理sqlSessionProxy使用一个模板方法封装了select()等操作,每一次select()查询都会自动先执行openSession(),执行完close()以后调用close()方法,相当于生成了一个新的session实例,所以我们无需手动的去关闭这个session()(关于这一点见下面mybatis的官方文档),当然也无法使用mybatis的一级缓存,也就是说mybatis的一级缓存在spring中是没有作用的.
官方文档摘要
MyBatis SqlSession provides you with specific methods to handle transactions programmatically. But when using MyBatis-Spring your beans will be injected with a Spring managed SqlSession or a Spring managed mapper. That means that Spring will always handle your transactions.
You cannot call SqlSession.commit(), SqlSession.rollback() or SqlSession.close() over a Spring managed SqlSession. If you try to do so, a UnsupportedOperationException exception will be thrown. Note these methods are not exposed in injected mapper classes.
二级缓存
二级缓存就是global caching,它超出session范围之外,可以被所有sqlSession共享,它的实现机制和mysql的缓存一样,开启它只需要在mybatis的配置文件开启settings里的
<setting name="cacheEnabled" value="true"/>
以及在相应的Mapper文件(例如userMapper.xml)里开启
<mapper namespace="dao.userdao"> ... select statement ... <!-- Cache 配置 --> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" /> </mapper>
需要注意的是global caching的作用域是针对Mapper的Namespace而言的,也就是说只在有在这个Namespace内的查询才能共享这个cache.例如上面的 dao.userdao namespace, 下面是官方文档的介绍
It's important to remember that a cache configuration and the cache instance are bound to the namespace of the SQL Map file. Thus, all statements in the same namespace as the cache are bound by it.
例如下面的示例,我们执行两次对同一个sql语句的查询,观察输出日志
@RequestMapping("/getUser") public String getUser(Model model) { User user = userDao.selectUserById(1); model.addAttribute(user); return "index"; }
当我们访问两次 /getUser 这个url,查看日志输出
DEBUG - Creating a new SqlSession
DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@659812] was not registered for synchronization because synchronization is not active
DEBUG - Cache Hit Ratio [dao.userdao]: 0.0
DEBUG - Fetching JDBC Connection from DataSource
DEBUG - JDBC Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver] will not be managed by Spring
DEBUG - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8, UserName=root@localhost, MySQL-AB JDBC Driver]
DEBUG - ==> Preparing: SELECT * FROM user WHERE id = ?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@659812]
DEBUG - Returning JDBC Connection to DataSource
DEBUG - Invoking afterPropertiesSet() on bean with name 'index'
DEBUG - Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/index.jsp]] in DispatcherServlet with name 'dispatcher'
DEBUG - Added model object 'org.springframework.validation.BindingResult.user' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'index'
DEBUG - Added model object 'user' of type [bean.User] to request in view with name 'index'
DEBUG - Forwarding to resource [/index.jsp] in InternalResourceView 'index'
DEBUG - Successfully completed request
DEBUG - Returning cached instance of singleton bean 'sqlSessionFactory'
DEBUG - DispatcherServlet with name 'dispatcher' processing GET request for [/user/getUser]
DEBUG - Looking up handler method for path /user/getUser
DEBUG - Returning handler method [public java.lang.String controller.UserController.getUser(org.springframework.ui.Model)]
DEBUG - Returning cached instance of singleton bean 'userController'
DEBUG - Last-Modified value for [/user/getUser] is: -1
DEBUG - Creating a new SqlSession
DEBUG - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@539a92] was not registered for synchronization because synchronization is not active
DEBUG - Cache Hit Ratio [dao.userdao]: 0.5
DEBUG - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@539a92]
DEBUG - Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/index.jsp]] in DispatcherServlet with name 'dispatcher'
DEBUG - Added model object 'org.springframework.validation.BindingResult.user' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'index'
DEBUG - Added model object 'user' of type [bean.User] to request in view with name 'index'
DEBUG - Forwarding to resource [/index.jsp] in InternalResourceView 'index'
DEBUG - Successfully completed request
可以看出第二次访问同一个url的时候相同的查询 hit cache了,这就是global cache的作用
The End
转:http://www.cnblogs.com/zemliu/archive/2013/08/05/3239014.html
相关推荐
MyBatis缓存(一级缓存、二级缓存)
mybatis支持缓存,如果我们查找数据库中某一条记录时,先从缓存中获取,如果缓存中不存在该记录,则从数据库中获取,在放入到缓存中。该文档是关于mybatis使用一级或二级缓存的介绍
通过log4j打印来查看mybatis缓存实现的机制, 原博客http://blog.csdn.net/zouxucong/article/details/68947052
Mybatis系列教程Mybatis缓存共17页.pdf.zip
Mybatis缓存开源架构源码2021.pdf
【MyBatis学习笔记八】——MyBatis缓存.zip 博客地址:https://blog.csdn.net/weixin_43817709/article/details/117601742
MyBatis缓存机制深度解剖[收集].pdf
介绍:一个很简单的Maven项目,对Mybatis的缓存进行测试
主要介绍了Mybatis 缓存原理及失效情况解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
springmvc整合Mybatis,Redis;实现将查询的数据进行二级缓存处理
主要介绍了MyBatis缓存实现原理及代码实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
mybatis的缓存配置文件,用于复制黏贴到配置文件中 yes
个人学习mybatis源码总结
学习MyBatis框架的一级缓存和二级缓存,明确缓存的工作机制,并实现MyBatis框架与第三方缓存EhCache的整合。
NULL 博文链接:https://jysemel.iteye.com/blog/2018922
主要介绍了MyBatis缓存功能原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要处理mybatis层对数据进行缓存处理问题,在数据底层进行优化
MyBatis缓存分为一级缓存和二级缓存一级缓存,本文给大家介绍mybatis缓存知识,非常不错具有参考借鉴价值,感兴趣的朋友一起学习吧
MyBatis整合Ehcache第三方缓存。