Mybatis缓存

Mybatis缓存

像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提
高性能。
Mybatis 中缓存分为一级缓存,二级缓存

 

1. Mybatis一级缓存

   1.1 证明一级缓存的存在

    一级缓存是session级别的缓存,只要sqlSession没有flush或者close,它就存在。无需配置

    1.1.1 编写用户持久层接口
/**
 * 用户的持久层接口
 * Ceate By llb on 2019/8/5
 */
public interface UserMapper {
    /**
     * 根据id查询用户
     * @return
     */
    User findUserById(int id);

}
    1.1.2 编写用户持久层映射文件

    

<?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.llb.dao.UserMapper">
    <!--useCache-->
    <select id="findUserById" resultType="user" parameterType="int" useCache="true">
        select * from user where id = #{id}
    </select>
</mapper>
    1.1.3 编写测试方法
package com.llb.test;

/**
 * Ceate By llb on 2019/8/5
 */
public class UserTest {

    InputStream in = null;
    UserMapper mapper = null;
    SqlSession sqlSession = null;
    SqlSessionFactory factory = null;
    /**
     * 在测试方法执行前执行
     * @throws IOException
     */
    @Before
    public void init() throws IOException {
        //1.读取配置文件,生成字节流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取sqlSessionFactory对象
        factory = new SqlSessionFactoryBuilder().build(in);
        //3.获取sqlSession对象
        sqlSession = factory.openSession();
        //4.获取dao的代理对象
        mapper = sqlSession.getMapper(UserMapper.class);
    }

    /**
     * 测试方法执行后执行
     * @throws IOException
     */
    @After
    public void destory() throws IOException {
        sqlSession.commit();
        //6.释放资源
        sqlSession.close();
        in.close();
    }
    /**
     * 根据id查询用户,sqlSession一级缓存:
     *  当调用sqlSession的修改、添加、删除,commit() ,close(),clear()等方法时,会清空缓存
     */
    @Test
    public void findUserById(){
        User user = mapper.findUserById(41);

        User user2 = mapper.findUserById(41);

        System.out.println(user == user2);
    }

}

    测试结果:

      

    

我们虽然查询了两次,但最后只查询了一次数据库,这就是Mybatis提供给我们得一级缓存起作用。因为一级缓存的存在,导致第二次查询id为41的记录时,并没有发出sql语句从数据库中查询数据,而是从一级缓存中查询。

    1.1.2 一级缓存的分析

      一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除时、commit、close等方法就会清空缓存。

 

第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息。
  得到用户信息,将用户信息存储到一级缓存中。
  如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
  第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息。

    2.1.3 测试一级缓存的清空

      

    /**
     * 根据id查询用户,sqlSession一级缓存:
     *  当调用sqlSession的修改、添加、删除,commit() ,close(),clear()等方法时,会清空缓存
     */
    @Test
    public void findUserById(){
        User user = mapper.findUserById(41);

        //关闭sqlSession会清空缓存
        sqlSession.close();
        sqlSession = factory.openSession();
        mapper = sqlSession.getMapper(UserMapper.class);

        //直接对sqlSession进行清空
//        sqlSession.clearCache();

        User user2 = mapper.findUserById(41);

        System.out.println(user == user2);
    }

当执行sqlSession.close()后,再次获取sqlSession并查询id=41的User对象时,又重新执行了sql 语句,从数据库进行了查询操作。导致两个用户的地址不一致。

 

2. Mybatis二级缓存(XML方式)

  二级缓存是mapper映射级别的缓存,多个sqlSession去操作同一个mapper映射的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的。

  2.1 二级缓存的结构图

    

       首先开启Mybatis的二级缓存。
    sqlSession1去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。
    当sqlSession2去查询同个用户信息时,首先会去二级缓存中查找是否存在数据,如果存在直接从缓存中取出数据。
    如果sqlSession3去执行相同mapper映射下sql,执行commit提交,将会清空该mapper映射下的二级缓存区域的数据。            

  

  2.2 二级缓存的开启与关闭

    2.2.1 第一步:在SqlMapConfig.xml文件开启二级缓存
<!--开启二级缓存,默认值为true,默认开启-->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    2.2.2 第二部:配置相关的Mapper映射文件
     
<cache>标签表示当前这个mapper映射将使用二级缓存,区分就看namespace的值

<?
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.llb.dao.UserMapper"> <!--开启user支持二级缓存--> <cache/> </mapper>
     2.2.3 第三步:配置statement上面的useCache属性
Mybatis缓存
<?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.llb.dao.UserMapper">

    <!--开启user支持二级缓存-->
    <cache/>
    <!--useCache,对该方法使用二级缓存-->
    <select id="findUserById" resultType="user" parameterType="int" useCache="true">
        select * from user where id = #{id}
    </select>
</mapper>
  
注意:针对每次查询都需要最新数据的sql,要设置成useCache=false,禁用二级缓存。

    2.2.3 二级缓存测试

    

package com.llb.test;
/**
 * Ceate By llb on 2019/8/5
 */
public class SecondLevelCache {

    InputStream in = null;
    SqlSessionFactory factory = null;
    /**
     * 在测试方法执行前执行
     * @throws IOException
     */
    @Before
    public void init() throws IOException {
        //1.读取配置文件,生成字节流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取sqlSessionFactory对象
        factory = new SqlSessionFactoryBuilder().build(in);
    }

    /**
     * 测试方法执行后执行
     * @throws IOException
     */
    @After
    public void destory() throws IOException {

        in.close();
    }


    /**
     * 根据id查询用户,二级缓存:
     *      存放的是数据,而不是对象
     */
    @Test
    public void findUserById(){

        SqlSession sqlSession = factory.openSession();
        UserMapper mapper1 = sqlSession.getMapper(UserMapper.class);

        User user1 = mapper1.findUserById(41);

        System.out.println(user1);

        //关闭缓存
        sqlSession.close();

        SqlSession sqlSession2 = factory.openSession();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);

        User user2 = mapper2.findUserById(41);

        System.out.println(user2);

        System.out.println(user1 == user2);
    }
}

  

  经过上面测试,我们发现执行了两次查询,并且在第一次查询后关闭了一级缓存,再去执行二级缓存时,我们发现并没有对数据库发出SQL语句,所以此时的数据就只能来自二级缓存
    2.2.4 二级缓存注意事项

    

当我们在使用二级缓存时,所缓存的类一定要实现java.io.Serializable接口,这种就可以使用序列化方式保存对象
package
com.llb.domain; import java.io.Serializable; /** * Ceate By llb on 2019/8/5 */ public class User implements Serializable{ private Integer id; private String username; private String address; private String sex; private Date birthday; }

 3. 使用注解实现二级缓存

  3.1 在SqlMapConfig中开启二级缓存支持

  

<!-- 配置二级缓存 --> 

<settings> <!-- 开启二级缓存的支持 -->

  <setting name="cacheEnabled" value="true"/> </settings>

  3.2 在持久层接口中使用注解配置二级缓存

package com.llb.dao;
import java.util.List;

//开启二级缓存
@CacheNamespace(blocking = true)
public interface UserMapper {

}

 

MyBatis注解开发

github:https://github.com/PopsiCola/SSM-mybatis/tree/cache 

欢迎star~

转载于:https://www.cnblogs.com/liulebin/p/11342087.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值