• Mybatis


    1. 概述

    与大多数持久层框架一下,Mybatis同样提供了一级缓存和二级缓存的支持。

    • 一级缓存:基于PerpetualCache的HashMap本地缓存,其存储作用域为Session,当Session做flush或close之后,该Session中的所有cache就将清空;
    • 二级缓存与一级缓存机制相同,默认也是采用PerpetualCache的HashMap存储,不同在于其存储作用域为Mapper(NameSpace),并且可自定义存储源,如Ehcache。

    注意:对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存NameSpace)进行了CUD操作后,默认该作用域下所有select中的缓存将被clear。

    2. 准备工作

    创建maven工程,目录结构如下:

    user表结构及数据:

    User类:

    public class User {
        private int id;
        private String user_name;
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getUser_name() {
            return user_name;
        }
        public void setUser_name(String user_name) {
            this.user_name = user_name;
        } 
        
    }  

    UserMapper类:

    public interface UserMapper {
     
        User selectUserById(int id);
        User selectUserByName(String name);
    }  

    mybatis-config.xml文件:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
      <properties resource="jdbc.properties" />
      <environments default="development">
        <environment id="development">
          <transactionManager type="JDBC"/>
          <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${user}"/>
            <property name="password" value="${pwd}"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="org/mybatis/mapper/UserMapper.xml"/>
      </mappers>
    </configuration>
    

    UserMapper.xml文件:

    <?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="org.mybatis.mapper.UserMapper">
      <select id="selectUserById" resultType="org.mybatis.mapper.User">
        select * from user where id = #{id}
      </select>
      
       <select id="selectUserByName" parameterType="java.lang.String" resultType="org.mybatis.mapper.User">
        select * from user where user_name = #{name};
      </select>
    </mapper>
    

    App类:

    public class App {
        public static void main(String[] args) throws IOException {
            String resource = "mybatis-config.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession session = sqlSessionFactory.openSession();
            try {
                UserMapper mapper = session.getMapper(UserMapper.class);
                User user = mapper.selectUserById(1);
                System.out.println(user.getUser_name());
                User u = mapper.selectUserByName("xiaoli");
                System.out.println(u.getId());
                session.commit();
            } finally {
                session.close();
            }
        }
    }  

    pom.xml文件增加如下依赖:

    <dependencies>
      <dependency>
       <groupId>org.mybatis</groupId>
       <artifactId>mybatis</artifactId>
       <version>3.4.4</version>
      </dependency>
      <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>5.1.36</version>
      </dependency>
      <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-log4j12</artifactId>
       <version>1.7.22</version>
      </dependency>
    
     </dependencies>
    

    3. 一级缓存

    mybatis会在标示会话的SqlSession对象中建立一个简单的本地缓存(local cache),每次查询到的结果缓存起来,当下次查询的时候,如果判断先前有个完全一样的查询,会直接从缓存中直接将结果取出,不需要再进行一次数据库查询了。

    一级缓存是SqlSession级别的缓存,在操作数据库时需要构造SqlSession,在对象中有一个内存区域数据结构HashMap用于存储缓存数据。不同SqlSession之间的缓存数据区域时互相不影响的。

    一级缓存的作用域是同一个SqlSession,在同一个SqlSession中两次执行相同的sql语句,当一个SqlSession结束后该SqlSession中的一级缓存也就不存在了,mybatis默认开启一级缓存。

     3.1 实例1:同一个SqlSession中两次查询id=1的记录

    public class App {
        public static void main(String[] args) throws IOException {
            String resource = "mybatis-config.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession session = sqlSessionFactory.openSession();
            try {
                UserMapper mapper = session.getMapper(UserMapper.class);
                User u1 = mapper.selectUserById(1);
                System.out.println(u1.getUser_name());
                // 利用缓存
                User u2 = mapper.selectUserById(1); 
                System.out.println(u2.getUser_name());
            } finally {
                session.close();
            }
        }
    }  

    截图:从日志可以看出,第二次相同sql语句的查询没有直接访问数据库,而是从缓存中获取。

    3.2 实例2:同一个SqlSession中一次查询id=1,另一次查询id=2的记录

    public class App {
        public static void main(String[] args) throws IOException {
            String resource = "mybatis-config.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession session = sqlSessionFactory.openSession();
            try {
                UserMapper mapper = session.getMapper(UserMapper.class);
                // id = 1
                User u1 = mapper.selectUserById(1);
                System.out.println(u1.getUser_name());
                // id = 2, 两次sql语句不同
                User u2 = mapper.selectUserById(2); 
                System.out.println(u2.getUser_name());
            } finally {
                session.close();
            }
        }
    }  

    结果截图:

    3.3 实例3:同一个SqlSession中两次查询id=1的记录,但是中途清除一级缓存

    public class App {
        public static void main(String[] args) throws IOException {
            String resource = "mybatis-config.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession session = sqlSessionFactory.openSession();
            try {
                UserMapper mapper = session.getMapper(UserMapper.class);
                // id = 1
                User u1 = mapper.selectUserById(1);
                System.out.println(u1.getUser_name());
                // 清除一级缓存
                session.clearCache();
                User u2 = mapper.selectUserById(1); 
                System.out.println(u2.getUser_name());
            } finally {
                session.close();
            }
        }
    }  

    截图:

    4. 二级缓存

    二级缓存是mapper级别的缓存,多个SqlSession去操作同一个mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

    二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同,即最终执行相同的sql语句,第一次执行完会将数据库中查询的数据写到缓存,第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。mybatis默认没有开启二级缓存需要在settings全局参数中配置开启二级缓存。

    4.1 使用二级缓存

    4.1.1 实体类User实现接口Serializable,否则报错

    Exception in thread "main" org.apache.ibatis.cache.CacheException: Error serializing object.  Cause: java.io.NotSerializableException: org.mybatis.mapper.User

    4.1.2 mybatis-config.xml增加配置

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

    必须开启缓存配置(默认是开启的),才能使用二级缓存。

    4.1.3 UserMapper.xml开启缓存

    <mapper namespace="org.mybatis.mapper.UserMapper">
       <cache/>
      <select id="selectUserById" resultType="org.mybatis.mapper.User">
        select * from user where id = #{id}
      </select>
      
       <select id="selectUserByName" parameterType="java.lang.String" resultType="org.mybatis.mapper.User">
        select * from user where user_name = #{name};
      </select>
    </mapper>  

    增加配置<cache />

    4.1.4 App.java和结果

    public class App {
        public static void main(String[] args) throws IOException {
            String resource = "mybatis-config.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession session1 = sqlSessionFactory.openSession();
            SqlSession session2 = sqlSessionFactory.openSession();
            try {
                UserMapper mapper1 = session1.getMapper(UserMapper.class);
                UserMapper mapper2 = session2.getMapper(UserMapper.class);
                // id = 1
                User u1 = mapper1.selectUserById(1);
                System.out.println(u1.getUser_name());
                // 第一个session必须提交才能使用二级缓存。
                session1.commit();
                User u2 = mapper2.selectUserById(1); 
                System.out.println(u2.getUser_name());
                
            } finally {
                session1.close();
                session2.close();
            }
        }
    }  

    截图:

    5. 总结

     mybatis一级缓存:默认开启

    (1)必须同一个SqlSession,如果SqlSession对象已经close,就不能用了;

    (2)查询条件必须一致;

    (3)没有执行过session.cleanCache()

    (4)没有执行过增删改操作(这些操作都会清理缓存)

    mybatis二级缓存:

    (1)mybatis-config.xml中默认配置

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

    (2)手动在Mapper.xml中添加<cache>

    <cache/> 有默认的参数值,比如

    <cache

    eviction="FIFO"  // 回收策略

    flushInterval="60000" // 自动刷新时间60秒

    size="512" // 最多缓存512个引用对象

    readOnly="true" // 只读

    />  

    (3)映射语句文件中的所有select语句将会被缓存

    (4)映射语句文件中的所有insert,update和delete语句会刷新缓存

    (5)缓存会使用Least Recently Used(LRU,最近最少使用)算法来收回

    (6)缓存会根据指定的时间间隔来刷新

    (7)缓存会默认存储1024个对象

    x. 参考资料

    https://my.oschina.net/KingPan/blog/280167

    https://www.cnblogs.com/little-fly/p/6251451.html

  • 相关阅读:
    博客作业06--图
    博客作业05--查找
    博客作业04--树
    博客作业03--栈和队列
    博客作业2---线性表
    博客作业01-抽象数据类型
    C语言最后一次博客作业
    C语言第十次博客作业--结构体
    C语言第九次博客作业--指针
    C语言第八次博客作业--字符数组
  • 原文地址:https://www.cnblogs.com/lujiango/p/8631744.html
Copyright © 2020-2023  润新知