Mybatis从入门到精通——二级缓存和一级缓存(16)

一、一级缓存和二级缓存

程序中缓存对系统效率的提升是极大的,在Mybatis中,缓存分别为一级缓存和二级缓存,其中一级缓存是默认开启的,二级缓存需要手动开启。

 

二、一级缓存

说明:

1.Mybatis的一级缓存是默认开启的。

2.若要停止Mybatis的一级缓存可以通过设置select标签上的flushCache属性为true,会每一次执行完查询就情况一级缓存。

3.一级缓存的生命周期是一个SqlSession,不能跨SqlSession域

4.该SqlSession下的任何增、删、改操作都会清空一级缓存

案例

mapepr映射文件

<?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.my.mapper.UserMapper">

  <resultMap id="BaseResultMap" type="com.my.entity.User">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="user_name" jdbcType="VARCHAR" property="userName" />
    <result column="real_name" jdbcType="VARCHAR" property="realName" />
    <result column="sex" jdbcType="CHAR" property="sex" />
    <result column="mobile" jdbcType="VARCHAR" property="mobile" />
    <result column="email" jdbcType="VARCHAR" property="email" />
    <result column="note" jdbcType="VARCHAR" property="note" />
    <result column="position_id" jdbcType="INTEGER" property="positionId" />
  </resultMap>

  <sql id="Base_Column_List">
    id, user_name, real_name, sex, mobile, email, note, position_id
  </sql>

  <!-- flushCache设置为true则为关闭一级缓存 -->
  <select id="selectById" parameterType="java.lang.Integer" resultMap="BaseResultMap" flushCache="false">
    select
    <include refid="Base_Column_List" />
    from user
    where id = #{id,jdbcType=INTEGER}
  </select>

  <update id="updateByUserSelective" parameterType="com.my.entity.User">
    update user
    <set>
      <if test="userName != null">
        user_name = #{userName,jdbcType=VARCHAR},
      </if>
      <if test="realName != null">
        real_name = #{realName,jdbcType=VARCHAR},
      </if>
      <if test="sex != null">
        sex = #{sex,jdbcType=CHAR},
      </if>
      <if test="mobile != null">
        mobile = #{mobile,jdbcType=VARCHAR},
      </if>
      <if test="email != null">
        email = #{email,jdbcType=VARCHAR},
      </if>
      <if test="note != null">
        note = #{note,jdbcType=VARCHAR},
      </if>
      <if test="positionId != null">
        position_id = #{positionId,jdbcType=INTEGER},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  
</mapper>

测试代码:

public class MybatisTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws IOException {
        String resource = "mybatis-config.xml";
        //1.使用mybatis的工具读取配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //2.创建sqlSessionFactory
        sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        inputStream.close();
    }

    /**
     * 测试一级缓存,需要通过查看日志的SQL打印判断是否缓存
     */
    @Test
    public void testOneCache() {
        //自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectById(1);
        //再次查询
        user = userMapper.selectById(1);
        user.setNote("test");
        //更新
        userMapper.updateByUserSelective(user);
        //再次查询
        user = userMapper.selectById(1);
        System.out.println(user);
        sqlSession.close();
    }

    /**
     * 测试一级缓存跨Session,需要通过查看日志的SQL打印判断是否缓存
     */
    @Test
    public void testOneCacheSession() {
        //自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
        User user = userMapper.selectById(1);
        User user2 = userMapper2.selectById(1);
        sqlSession.close();
        sqlSession2.close();
    }


}

说明:缓存效果不能通过代码直接看到,需要自己debug查看打印日志进行观察。

 

三、二级缓存

说明:

1.二级缓存默认是不使用的,需要手动添加。

2.二级缓存需要把Mybatis配置文件中的cacheEnabled设为true(默认是true,但设置后更直观)。

3.开启二级缓存后还需要去mapper.xml文件中通过使用cache或cache-ref开启二级缓存的使用。

4.二级缓存的生命周期是一个SqlSessionFactory(一般一个项目中只用一个)。

5.二级缓存是跨SqlSession的,但是并不跨命名空间(每个mapper.xml)。

6.同一个命名空间下的任意SqlSession的增、删、改操作都会清空二级缓存。

cache和cache-ref标签介绍:

cache标签用在mapper.xml文件中,开启该命名空间的二级缓存,和cache-ref标签冲突,常用三个属性:

    1.eviction:缓存策略,一般用FIFO

    2.flushInterval:多久清空一次,单位秒

    3.size:缓存列表数量

cache-ref标签用在mapper.xml文件中,和其它命名空间共用一个缓存,和cache标签冲突,只有一个属性:

    1.namespace:需要其共用缓存的命名空间(该值的命名空间需要开启二级缓存)

案例:

mapper映射文件:

<?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.my.mapper.PositionMapper">

  <!-- 开启二级缓存,使用默认配置 -->
  <cache> </cache>

<!-- 和其它命名空间共用一个缓存 -->
<!--  <cache-ref namespace="命名空间"/>-->
  
  <resultMap id="BaseResultMap" type="com.my.entity.Position">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="posname" jdbcType="VARCHAR" property="posname" />
    <result column="note" jdbcType="VARCHAR" property="note" />
  </resultMap>
  
  <sql id="Base_Column_List">
    id, posname, note
  </sql>
  
  <select id="selectById" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from position
    where id = #{id,jdbcType=INTEGER}
  </select>

  <update id="updateByPositionSelective" parameterType="com.my.entity.Position">
    update position
    <set>
      <if test="posname != null">
        posname = #{posname,jdbcType=VARCHAR},
      </if>
      <if test="note != null">
        note = #{note,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

测试代码:

public class MybatisTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws IOException {
        String resource = "mybatis-config.xml";
        //1.使用mybatis的工具读取配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //2.创建sqlSessionFactory
        sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        inputStream.close();
    }


    /**
     * 测试二级缓存,需要通过查看日志的SQL打印判断是否缓存
     */
    @Test
    public void testTowCache() {
        //自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        PositionMapper positionMapper = sqlSession.getMapper(PositionMapper.class);
        PositionMapper positionMapper2 = sqlSession2.getMapper(PositionMapper.class);
        Position position = positionMapper.selectById(1);
        //再次查询
        position = positionMapper.selectById(1);
        position.setNote("test");
        //更新
        positionMapper.updateByPositionSelective(position);
        //再次查询
        position = positionMapper.selectById(1);
        System.out.println(position);
        sqlSession.close();
    }

}

说明:缓存效果不能通过代码直接看到,需要自己debug查看打印日志进行观察。

 

四、补充说明

1.缓存之间执行的顺序,二级缓存—一级缓存—数据库

2.一般不用二级缓存,因为二级缓存可能会造成脏读,例如A命名空间开启了二级缓存,当B命名空间对A命名空间中的表进行修改时,A命名空间的缓存是无法知晓的。

发布了60 篇原创文章 · 获赞 81 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/m0_37914588/article/details/104755642