zoukankan      html  css  js  c++  java
  • 06—mybatis缓存机制

    MyBatis缓存分为一级缓存和二级缓存

    一级缓存
    MyBatis的一级缓存指的是在一个Session域内,session为关闭的时候执行的查询会根据SQL为key被缓存(跟mysql缓存一样,修改任何参数的值都会导致缓存失效)

    1.创建表
    CREATE TABLE `tb_user` (
      `id` INT(11) NOT NULL AUTO_INCREMENT,
      `name` VARCHAR(18) DEFAULT NULL,
      `sex` CHAR(2) DEFAULT NULL,
      `age` INT(11) DEFAULT NULL,
      PRIMARY KEY  (`id`)
    )
    INSERT INTO `mybatis`.`tb_user` (`name`, `sex`, `age`) VALUES('1111', '男', 20) ;
    INSERT INTO `mybatis`.`tb_user` (`name`, `sex`, `age`) VALUES('2222', '女', 22) ;
    INSERT INTO `mybatis`.`tb_user` (`name`, `sex`, `age`) VALUES('3333', '女', 23) ;
    INSERT INTO `mybatis`.`tb_user` (`name`, `sex`, `age`) VALUES('4444', '男', 24) ;
    INSERT INTO `mybatis`.`tb_user` (`name`, `sex`, `age`) VALUES('5555', '女', 25) ;
    

     2.创建model

     User.java

    package org.fkit.domain;
    import java.io.Serializable;
    public class User implements Serializable{
        private Integer id;
        private String name;
        private String sex;
        private Integer age;
        public User() {
            super();
        }
        public User( String name, String sex, Integer age) {
            super();
            this.name = name;
            this.sex = sex;
            this.age = age;
        }
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getSex() {
            return sex;
        }
        public void setSex(String sex) {
            this.sex = sex;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "User [id=" + id + ", name=" + name + ", sex=" + sex + ", age="
                    + age + "]";
        }
    }

    3.mapper.java和mapper.xml
    UserMapper.java

    package org.fkit.mapper;
    import java.util.List;
    import org.fkit.domain.User;
    public interface UserMapper {
        // 根据id查询User
        User selectUserById(Integer id);
        // 查询所有User
        List<User> selectAllUser();
        // 根据id删除User
        void deleteUserById(Integer id);
    }

    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">
    <!-- namespace指用户自定义的命名空间。 -->
    <mapper namespace="org.fkit.mapper.UserMapper">
      <!-- 根据id查询User -->
      <select id="selectUserById" parameterType="int" 
      resultType="org.fkit.domain.User">
          SELECT * FROM TB_USER WHERE id = #{id}
      </select>
      <!-- 查询所有User -->
      <select id="selectAllUser" resultType="org.fkit.domain.User">
          SELECT * FROM TB_USER 
      </select>
      <!-- 根据id删除User -->
      <delete id="deleteUserById" parameterType="int">
          DELETE FROM TB_USER WHERE id = #{id}
      </delete>
    </mapper>

     4.mybatis-config.xml

    db.properties

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/mybatis
    username=root
    password=123456

    log4j.properties

    # Global logging configuration
    log4j.rootLogger=ERROR, stdout
    # MyBatis logging configuration...
    log4j.logger.org.fkit.mapper.UserMapper=DEBUG
    # Console output...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

    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">
      <!--  XML 配置文件包含对 MyBatis 系统的核心设置 -->
    <configuration>
        <properties resource="db.properties"/>
        <!-- 指定 MyBatis 所用日志的具体实现 -->
        <settings>
            <setting name="logImpl" value="LOG4J"/>
        </settings>
        <!-- 设置别名 -->
        <typeAliases>
            <typeAlias  alias="user" type="org.fkit.domain.User"/>
        </typeAliases>
        <environments default="mysql">
        <!-- 环境配置,即连接的数据库。 -->
        <environment id="mysql">
        <!--  指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 -->
          <transactionManager type="JDBC"/>
          <!--  dataSource指数据源配置,POOLED是JDBC连接对象的数据源连接池的实现。 -->
          <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
      <!-- mappers告诉了MyBatis去哪里找持久化类的映射文件 -->
      <mappers>
          <mapper resource="org/fkit/mapper/UserMapper.xml"/>
      </mappers>
    </configuration>

    5.测试

    (1).封装factory

    package org.fkit.factory;
    import java.io.InputStream;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    public class FKSqlSessionFactory {
        private static SqlSessionFactory sqlSessionFactory = null;
        // 初始化创建SqlSessionFactory对象
        static{
            try {
                // 读取mybatis-config.xml文件
                InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
                sqlSessionFactory = new SqlSessionFactoryBuilder()
                        .build(inputStream);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 获取SqlSession对象的静态方法
        public static SqlSession getSqlSession(){
            return sqlSessionFactory.openSession();
        }
        // 获取SqlSessionFactory的静态方法
        public static SqlSessionFactory getSqlSessionFactory() {
            return sqlSessionFactory;
        }
    }

    (2).测试类

    package org.fkit.test;
    import org.apache.ibatis.session.SqlSession;
    import org.fkit.domain.User;
    import org.fkit.factory.FKSqlSessionFactory;
    import org.fkit.mapper.UserMapper;
    
    public class TestOneLevelCache {
    
        public static void main(String[] args) throws Exception {
            TestOneLevelCache t = new TestOneLevelCache();    
            t.testCache1(); //sql只被执行一次
    //        t.testCache2();
    //        t.testCache3();
        }
         /*
          * 一级缓存: 也就Session级的缓存(默认开启)
          */
        public void testCache1 (){
            // 使用工厂类获得SqlSession对象
            SqlSession session = FKSqlSessionFactory.getSqlSession();
            // 获得UserMapping对象
            UserMapper um = session.getMapper(UserMapper.class);
            // 查询id为1的User对象,会执行select语句
            User user = um.selectUserById(1);
            System.out.println(user);
            // 再次查询id为1的User对象,因为是同一个SqlSession,所以会从之前的一级缓存中查找数据
            User user2 = um.selectUserById(1);
            System.out.println(user2);
            // 关闭SqlSession对象
            session.close();
        }
        public void testCache2 (){
            // 使用工厂类获得SqlSession对象
            SqlSession session = FKSqlSessionFactory.getSqlSession();
            // 获得UserMapping对象
            UserMapper um = session.getMapper(UserMapper.class);
            // 查询id为1的User对象,会执行select语句
            User user = um.selectUserById(1);
            System.out.println(user);
            // 执行delete操作
            um.deleteUserById(5);
            // commit提交
            session.commit();
            // 再次查询id为1的User对象,因为DML操作会清空SqlSession缓存,所以会再次执行select语句
            User user2 = um.selectUserById(1);
            System.out.println(user2);
            // 关闭SqlSession对象
            session.close();
        }
        public void testCache3 (){
            // 使用工厂类获得SqlSession对象
            SqlSession session = FKSqlSessionFactory.getSqlSession();
            // 获得UserMapping对象
            UserMapper um = session.getMapper(UserMapper.class);
            // 查询id为1的User对象,会执行select语句
            User user = um.selectUserById(1);
            System.out.println(user);
            // 关闭一级缓存
            session.close();
            // 再次访问,需要再次获取一级缓存,然后才能查找数据,否则会抛出异常
            session = FKSqlSessionFactory.getSqlSession();
            // 再次获得UserMapping对象
            um = session.getMapper(UserMapper.class);
            // 再次访问,因为现在使用的是一个新的SqlSession对象,所以会再次执行select语句
            User user2 = um.selectUserById(1);
            System.out.println(user2);
            // 关闭SqlSession对象
            session.close();
        }
    }
    知识点分析:
    testCache1结果
    DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
    DEBUG [main] - ==> Parameters: 1(Integer)
    DEBUG [main] - <==      Total: 1
    User [id=1, name=1111, sex=男, age=20]
    User [id=1, name=1111, sex=男, age=20]
    这里只执行了一条sql语句
     
    testCache2结果
    DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
    DEBUG [main] - ==> Parameters: 1(Integer)
    DEBUG [main] - <==      Total: 1
    User [id=1, name=1111, sex=男, age=20]
    DEBUG [main] - ==>  Preparing: DELETE FROM TB_USER WHERE id = ? 
    DEBUG [main] - ==> Parameters: 5(Integer)
    DEBUG [main] - <==    Updates: 1
    DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
    DEBUG [main] - ==> Parameters: 1(Integer)
    DEBUG [main] - <==      Total: 1
    User [id=1, name=1111, sex=男, age=20]
    这里用了session.commit();已经提交了操作,所以sqlsession缓存被清空,所以会执行sql语句
     
    testCache3结果
    DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
    DEBUG [main] - ==> Parameters: 1(Integer)
    DEBUG [main] - <==      Total: 1
    User [id=1, name=1111, sex=男, age=20]
    DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
    DEBUG [main] - ==> Parameters: 1(Integer)
    DEBUG [main] - <==      Total: 1
    User [id=1, name=1111, sex=男, age=20]
    这里关闭了sqlsession(session.close())所以缓存是一个新的对象。
     
    二级缓存
    二级缓存就是global caching,它超出session范围之外,可以被所有sqlSession共享,它的实现机制和mysql的缓存一样,开启它只需要在mybatis的配置文件开启settings里的
    <setting name="cacheEnabled" value="true"/>

    1.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">
      <!--  XML 配置文件包含对 MyBatis 系统的核心设置 -->
    <configuration>
        <properties resource="db.properties"/>
        <!-- 指定 MyBatis 所用日志的具体实现 -->
        <settings>
            <setting name="logImpl" value="LOG4J"/>
            <!-- 开启二级缓存 -->
            <setting name="cacheEnabled" value="true"/>
        </settings>
        <!-- 设置别名 -->
        <typeAliases>
            <typeAlias  alias="user" type="org.fkit.domain.User"/>
        </typeAliases>
        <environments default="mysql">
        <!-- 环境配置,即连接的数据库。 -->
        <environment id="mysql">
        <!--  指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 -->
          <transactionManager type="JDBC"/>
          <!--  dataSource指数据源配置,POOLED是JDBC连接对象的数据源连接池的实现。 -->
          <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
      <!-- mappers告诉了MyBatis去哪里找持久化类的映射文件 -->
      <mappers>
          <mapper resource="org/fkit/mapper/UserMapper.xml"/>
      </mappers>
    </configuration>

    2.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">
    <!-- namespace指用户自定义的命名空间。 -->
    <mapper namespace="org.fkit.mapper.UserMapper">
        <!-- 开启二级缓存 
           回收策略为先进先出
           自动刷新时间60s
           最多缓存512个引用对象
           只读
    eviction:收回策略,默认为LRU。
                  LRU:最近最少使用的策略,移除最长时间不被使用的对像。
        FIFO:先进先出策略,按对像进入缓存的顺序来移除它们。
        SOFT:软引用策略,移除基于垃圾回收器的状态和软引用规则的对像。
        WEAK:弱引用策略,更积极地移除基于垃圾收集器的状态和弱引用规则的对像。
    flushInterval:刷新间隔,毫秒为单位。
    size:缓存数目。默认值1024。
    readOnly:只读,默认是false。
       -->
        <cache 
        eviction="LRU"  
        flushInterval="60000" 
        size="512" 
        readOnly="true"/> 
      <!-- 根据id查询User -->
      <select id="selectUserById" parameterType="int" 
      resultType="org.fkit.domain.User" useCache='true'>
          SELECT * FROM TB_USER WHERE id = #{id}
      </select>
      <!-- 查询所有User -->
      <select id="selectAllUser" resultType="org.fkit.domain.User">
          SELECT * FROM TB_USER 
      </select>
      <!-- 根据id删除User -->
      <select id="deleteUserById" parameterType="int">
          DELETE FROM TB_USER WHERE id = #{id}
      </select>
    </mapper>

    3.测试

    TestTwoLevelCache.java

    package org.fkit.test;
    import org.apache.ibatis.session.SqlSession;
    import org.fkit.domain.User;
    import org.fkit.factory.FKSqlSessionFactory;
    import org.fkit.mapper.UserMapper;
    public class TestTwoLevelCache {
        public static void main(String[] args) throws Exception {
            TestTwoLevelCache t = new TestTwoLevelCache();
            //t.testCache1();
            t.testCache2();
        }
        
        public void testCache1 (){
            // 使用工厂类获得SqlSession对象
            SqlSession session = FKSqlSessionFactory.getSqlSession();
            // 获得UserMapping对象
            UserMapper um = session.getMapper(UserMapper.class);
            // 查询id为1的User对象,会执行select语句
            User user = um.selectUserById(1);
            System.out.println(user);
            // 执行delete操作
            um.deleteUserById(5);
            // commit提交
            session.commit();
            // 再次查询id为1的User对象,因为DML操作会清空SqlSession缓存,所以会再次执行select语句
            User user2 = um.selectUserById(1);
            System.out.println(user2);
            // 关闭SqlSession对象
            session.close();
        }
        
        public void testCache2 (){
            // 使用工厂类获得SqlSession对象
            SqlSession session = FKSqlSessionFactory.getSqlSession();
            // 获得UserMapping对象
            UserMapper um = session.getMapper(UserMapper.class);
            // 查询id为1的User对象,会执行select语句
            User user = um.selectUserById(2);
            System.out.println(user);
            // 关闭一级缓存
            session.close();
            // 再次访问,需要再次获取一级缓存,然后才能查找数据,否则会抛出异常
            session = FKSqlSessionFactory.getSqlSession();
            // 再次获得UserMapping对象
            um = session.getMapper(UserMapper.class);
            // 再次访问,因为现在使用的是一个新的SqlSession对象,所以会再次执行select语句
            User user2 = um.selectUserById(2);
            System.out.println(user2);
            // 关闭SqlSession对象
            session.close();
        }
    }
    知识点分析:
    testCache1结果
    DEBUG [main] - Cache Hit Ratio [org.fkit.mapper.UserMapper]: 0.0
    DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
    DEBUG [main] - ==> Parameters: 2(Integer)
    DEBUG [main] - <==      Total: 1
    User [id=2, name=22222, sex=2, age=19]
    DEBUG [main] - Cache Hit Ratio [org.fkit.mapper.UserMapper]: 0.0
    DEBUG [main] - ==>  Preparing: DELETE FROM TB_USER WHERE id = ? 
    DEBUG [main] - ==> Parameters: 5(Integer)
    DEBUG [main] - Cache Hit Ratio [org.fkit.mapper.UserMapper]: 0.3333333333333333
    User [id=2, name=22222, sex=2, age=19]
    testCache2结果
    DEBUG [main] - Cache Hit Ratio [org.fkit.mapper.UserMapper]: 0.0
    DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
    DEBUG [main] - ==> Parameters: 2(Integer)
    DEBUG [main] - <==      Total: 1
    User [id=2, name=22222, sex=2, age=19]
    DEBUG [main] - Cache Hit Ratio [org.fkit.mapper.UserMapper]: 0.5
    User [id=2, name=22222, sex=2, age=19]
  • 相关阅读:
    触发器
    变量
    Python 3.6 抓取微博m站数据
    Linux cp/rm/mv 强制覆盖
    Oracle的CLOB大数据字段类型
    4、NameNode启动过程详解
    2、HDFS交互式Shell
    1、HDFS 架构、启动过程
    11、 Hadoop 2.x各个服务组件如何配置在那台服务器运行并测试
    10、Hadoop组件启动方式和SSH无密码登陆
  • 原文地址:https://www.cnblogs.com/itmu89/p/6531065.html
Copyright © 2011-2022 走看看