继上一篇笔记 SSM系列3 Mybatis快速上手,今天学习了一下Mybatis的分页组件与缓存策略,直接上干货
Mybatis缓存策略有两级缓存:
一级缓存:默认开启,缓存范围为一次SqlSession会话,session关闭,该缓存即清空
二级缓存:手动开启,缓存范围为mapper的namespace中,比一级缓存范围大,生存时间长
一级缓存无论何种操作,进行了commit之后都会被清空
二级缓存的commit的操作,只有在写操作commit之后才会被清空,查询后的commit操作不会清空缓存
代码演示:
/*缓存测试*/
@Test
public void testFindById(){
SqlSession session = null;
try {
session = sessionFactory.openSession();
Goods goods = session.selectOne("goods.findById",739);
System.out.println("session1-对象1:"+goods);
Goods goods2 = session.selectOne("goods.findById",739);
System.out.println("session1-对象2:"+goods2);
}catch (Exception e){
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
try {
session = sessionFactory.openSession();
Goods goods = session.selectOne("goods.findById",739);
System.out.println("session2-对象1:"+goods);
}catch (Exception e){
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
}
我们看如下结果,在同一个session中,进行两次查询,但是只去数据库查询了一次,并且两次接收到的对象是同一个对象,在第二个session中查询同一条数据,又去数据库查询了一次,这说明一级缓存的作用域是一个session会话周期
/*缓存测试*/
@Test
public void testFindById(){
SqlSession session = null;
try {
session = sessionFactory.openSession();
Goods goods = session.selectOne("goods.findById",739);
System.out.println("session1-对象1:"+goods);
session.commit();//清空缓存
Goods goods2 = session.selectOne("goods.findById",739);
System.out.println("session1-对象2:"+goods2);
}catch (Exception e){
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
}
看下图结果,去数据库进行了两次查询,并且对象也不一样,所以commit清空缓存的成立的
一级缓存可以使用flushCache禁用,用法是在相关的mapper.xml的Sql标签后面加上flushCache=“true”
flushCache:强制清空缓存,并且该Sql执行后无论得到什么结果都不会对其进行缓存
<select id="findById" parameterType="Integer" resultType="com.zhangyx.mybatis.entity.Goods" flushCache="true">
select * from t_goods where goods_id = #{value }
select>
继续用刚才的测试代码测试,结果如下,下面我也不说太多了,自己看代码,看结果
二级缓存开启就需要一些配置了
mybatis-config.xml里settings里增加setting项,开启二级缓存
<setting name="cacheEnabled" value="true"/>
相应的mapper.xml我这里是goods.xml里增加cache标签
<cache eviction="LRU" flushInterval="6000000" size="512" readOnly="true"/>
记得把flushCache选项去掉,这个在二级缓存里也是起作用的
/*缓存测试*/
@Test
public void testFindById(){
SqlSession session = null;
try {
session = sessionFactory.openSession();
Goods goods = session.selectOne("goods.findById",739);
System.out.println("session1-对象1:"+goods);
}catch (Exception e){
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
try {
session = sessionFactory.openSession();
Goods goods = session.selectOne("goods.findById",739);
System.out.println("session2-对象1:"+goods);
}catch (Exception e){
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
}
结果:第二次也没有去数据库进行查询,直接将第一次查询的缓存对象取出来了
一级缓存清空策略上面已经说过了,利用commit,与flushCache可以清空缓存
二级缓存不一样喽,可以利用flushCache="true"清空缓存,useCache="false"禁用缓存
flushCache刚才已经说过了,这里不再说了,大家可以自己测试,这里说一下useCache="false"禁用缓存,跟flushCache一样,在Sql相关标签上加上即可
<select id="findById" parameterType="Integer" resultType="com.zhangyx.mybatis.entity.Goods" useCache="false">
select * from t_goods where goods_id = #{value }
select>
/*缓存测试*/
@Test
public void testFindById(){
SqlSession session = null;
try {
session = sessionFactory.openSession();
Goods goods = session.selectOne("goods.findById",739);
System.out.println("session1-对象1:"+goods);
}catch (Exception e){
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
try {
session = sessionFactory.openSession();
Goods goods = session.selectOne("goods.findById",739);
System.out.println("session2-对象1:"+goods);
}catch (Exception e){
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
}
写操作都没有缓存,因为写操作上面的flushCache默认是开启的,就以更新为例看一下
@Test
public void testUpdate(){
SqlSession session = null;
//openSession创建一个新的Sqlsession对象,Sqlsession提供了增删改查的方法调用
try {
session = sessionFactory.openSession();
Goods goods = session.selectOne("goods.findById",2675);
System.out.println(goods);
goods.setTitle("数据更新测试");
goods.setSubTitle("数据更新测试第二标题");
goods.setCategoryId(1);
goods.setCurrentPrice(1000f);
goods.setDiscount(2f);
goods.setIsFreeDelivery(1);
goods.setOriginalCost(20f);
session.update("goods.update", goods);
// session.commit();//清队缓存干扰去掉
}catch (Exception e){
e.printStackTrace();
session.rollback();
}finally {
if(session != null){
//将Connection归还到连接池供其他Session重用
session.close();
}
}
try {
session = sessionFactory.openSession();
Goods goods1 = session.selectOne("goods.findById",2675);
System.out.println(goods1);
}catch (Exception e){
e.printStackTrace();
}finally {
if(session != null){
session.close();
}
}
}
其实官网有详细教程:https://pagehelper.github.io/docs/howtouse/
1.引入PageHelper与jsqlparser核心jar包
2.mybatis-config.xml增加有关PageHelper的Plugin配置
3.代码中查询数据库代码的上方直接使用PageHelper.startPage()自动分页
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.1.4version>
dependency>
<dependency>
<groupId>com.github.jsqlparsergroupId>
<artifactId>jsqlparserartifactId>
<version>0.9.5version>
dependency>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="helperDialect" value="mysql"/>
<property name="reasonable" value="true"/>
plugin>
plugins>
@Test
public void testFindAll(){
SqlSession session = null;
//openSession创建一个新的Sqlsession对象,Sqlsession提供了增删改查的方法调用
try {
session = sessionFactory.openSession();
//selectList用于查询多条数据
//表.xml里对应的namespace.sqlId
//分页组件,直接在查询代码上方加入PageHelper.startPage()即可
PageHelper.startPage(0,10);
List<Goods> list = session.selectList("goods.findAll");
for (Goods goods : list){
System.out.println(goods.getTitle());
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(session != null){
//将Connection归还到连接池供其他Session重用
session.close();
}
}
}
如果分页插件里指定的跟自己使用的数据库不一样,比如说指定了oracle,但是我们使用的是mysql会发生什么情况呢
我们看到,虽然指定的数据库错了,但是分页组件还是按照oracle的形式把要其所用的sql语句组装了起来,只不过组装的是oracle可以用的分页语句
Mybatis告一段落,但是在实际项目开发中,sqlSessionFactory不是这样使用的,需要配置到xml文件里的,会在我后面的笔记:Spring SpringMVC Mybatis FreeMarker 整合里作记录