zoukankan      html  css  js  c++  java
  • Mybatis 系列9-缓存

    像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。
    Mybatis 中缓存分为一级缓存,二级缓存。
    一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。
    一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。

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

    一级缓存

    为了看的更清楚,重新创建个maven工程
    1、pom文件:

    <packaging>jar</packaging>
        <dependencies>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.3</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.6</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
        </dependencies>
    

    2、resource创建log4j.properties、jdbcConfig.properties、SqlMapConfig.xml

    # Set root category priority to INFO and its only appender to CONSOLE.
    #log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
    log4j.rootCategory=debug, CONSOLE, LOGFILE
    
    # Set the enterprise logger category to FATAL and its only appender to CONSOLE.
    log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
    
    # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m
    
    
    # LOGFILE is set to be a File appender using a PatternLayout.
    log4j.appender.LOGFILE=org.apache.log4j.FileAppender
    log4j.appender.LOGFILE.File=d:axis.log
    log4j.appender.LOGFILE.Append=true
    log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m
    
    
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/db2
    jdbc.username=root
    jdbc.password=123456
    
    <?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-->
        <properties resource="jdbcConfig.properties"></properties>
    
        <!--<settings>
            <setting name="cacheEnabled" value="true"/>
        </settings>-->
    
        <!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
        <typeAliases>
            <package name="com.mantishell.domain"></package>
        </typeAliases>
    
        <!--配置环境-->
        <environments default="mysql">
            <!-- 配置mysql的环境-->
            <environment id="mysql">
                <!-- 配置事务 -->
                <transactionManager type="JDBC"></transactionManager>
    
                <!--配置连接池-->
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"></property>
                    <property name="url" value="${jdbc.url}"></property>
                    <property name="username" value="${jdbc.username}"></property>
                    <property name="password" value="${jdbc.password}"></property>
                </dataSource>
            </environment>
        </environments>
        <!-- 配置映射文件的位置 -->
        <mappers>
            <package name="com.mantishell.dao"></package>
        </mappers>
    </configuration>
    

    3、创建持久层的配置文件com/mantishell.dao/IUserDao.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="com.mantishell.dao.IUserDao">
        <!--开启二级缓存-->
        <!--<cache />-->
    
        <!-- 查询所有 -->
        <select id="findAll" resultType="user">
            select * from user
        </select>
    
        <!-- 根据id查询用户 -->
        <select id="findById" parameterType="INT" resultType="user" useCache="true">
            select * from user where id = #{uid}
        </select>
    
        <!-- 更新用户信息-->
        <update id="updateUser" parameterType="user">
            update user set username=#{username},address=#{address} where id=#{id}
        </update>
    </mapper>
    

    4、创建实体

    package com.mantishell.domain;
    
    import java.io.Serializable;
    import java.util.Date;
    
    public class User implements Serializable {
        private Integer id;
        private String username;
        private String address;
        private String sex;
        private Date birthday;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    }
    
    

    5、持久层接口:

    package com.mantishell.dao;
    
    import com.mantishell.domain.User;
    
    import java.util.List;
    
    public interface IUserDao {
        /**
         * 查询所有用户,同时获取到用户下所有账户的信息
         * @return
         */
        List<User> findAll();
    
    
        /**
         * 根据id查询用户信息
         * @param userId
         * @return
         */
        User findById(Integer userId);
    
        /**
         * 更新用户信息
         * @param user
         */
        void updateUser(User user);
    }
    
    

    6、测试

    /**
         * 测试一级缓存
         */
        @Test
        public void testFirstLevelCache(){
            User user1 = userDao.findById(41);
            System.out.println(user1);
    
            userDao = sqlSession.getMapper(IUserDao.class);
    
            User user2 = userDao.findById(41);
            System.out.println(user2);
    
            System.out.println(user1 == user2);
        }
    

    结果是:

    com.mantishell.domain.User@282003e1
    2020-03-17 22:16:36,821 554    [           main] DEBUG    com.mantishell.dao.IUserDao  - Cache Hit Ratio [com.mantishell.dao.IUserDao]: 0.0
    com.mantishell.domain.User@282003e1
    true
    

    可以看出第二次查询时并没有去数据库中查找,而是从缓存里取的。

    当把sqlSession关闭掉或清空缓存:

    @Test
        public void testFirstLevelCache(){
            User user1 = userDao.findById(41);
            System.out.println(user1);
    
            sqlSession.close();
            //再次获取SqlSession对象
            sqlSession = factory.openSession();
    
            //sqlSession.clearCache();//此方法也可以清空缓存
    
            userDao = sqlSession.getMapper(IUserDao.class);
    
            User user2 = userDao.findById(41);
            System.out.println(user2);
    
            System.out.println(user1 == user2);
        }
    

    结果是:

    com.mantishell.domain.User@6e2c9341
    2020-03-17 22:26:28,239 619    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@543e710e]
    2020-03-17 22:26:28,239 619    [           main] DEBUG source.pooled.PooledDataSource  - Returned connection 1413378318 to pool.
    2020-03-17 22:26:28,239 619    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Opening JDBC Connection
    2020-03-17 22:26:28,240 620    [           main] DEBUG source.pooled.PooledDataSource  - Checked out connection 1413378318 from pool.
    2020-03-17 22:26:28,240 620    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@543e710e]
    2020-03-17 22:26:28,242 622    [           main] DEBUG ntishell.dao.IUserDao.findById  - ==>  Preparing: select * from user where id = ? 
    2020-03-17 22:26:28,242 622    [           main] DEBUG ntishell.dao.IUserDao.findById  - ==> Parameters: 41(Integer)
    2020-03-17 22:26:28,247 627    [           main] DEBUG ntishell.dao.IUserDao.findById  - <==      Total: 1
    com.mantishell.domain.User@4e4aea35
    false
    

    显然从数据库查询了两次。

    二级缓存

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

    二级缓存需要手动开启
    sqlSession1查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。
    此时如果SqlSession3去执行相同mapper映射下的sql语句,执行commit提交,将会清空该mapper映射下的二级缓存区的数据。
    SqlSession2去查询与SqlSession1相同的用户信息,首先会去缓存中找是否存在数据,如果存在直接从缓存中取出数据。

    二级缓存的开启和关闭

    1、在SqlMapConfig.xml 文件开启二级缓存

        <!--开启二级缓存-->
        <settings>
            <setting name="cacheEnabled" value="true"/>
        </settings>
    

    cacheEnabled的取值默认是true,所以这一步可以省略。true-表示开启;false-表示关闭

    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.mantishell.dao.IUserDao">
        <!--开启二级缓存-->
        <cache />
    
        <!-- 根据id查询用户 -->
        <select id="findById" parameterType="INT" resultType="user" useCache="true">
            select * from user where id = #{uid}
        </select>
    

    <select>标签中设置useCache=”true”代表当前这个statement要使用二级缓存,如果不使用二级缓存可以设置为false。
    注意:如果每次查询都需要最新的数据,那么需要设置为useCache=false,禁用二级缓存。

    测试:

        @Test
        public void testFirstLevelCache(){
            SqlSession sqlSession1 = factory.openSession();
            IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
            User user1 = dao1.findById(41);
            System.out.println(user1);
            sqlSession1.close();//一级缓存消失
    
            SqlSession sqlSession2 = factory.openSession();
            IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
            User user2 = dao2.findById(41);
            System.out.println(user2);
            sqlSession2.close();
    
            System.out.println(user1 == user2);
        }
    
    

    首先关闭了一级缓存,免得影响后面结果。从结果可以看出,两次查询中sql只执行一次,也就是说是从二级缓存中取的值

    2020-03-17 22:54:17,508 287    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Opening JDBC Connection
    2020-03-17 22:54:17,904 683    [           main] DEBUG source.pooled.PooledDataSource  - Created connection 392781299.
    2020-03-17 22:54:17,904 683    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@17695df3]
    2020-03-17 22:54:17,912 691    [           main] DEBUG ntishell.dao.IUserDao.findById  - ==>  Preparing: select * from user where id = ? 
    2020-03-17 22:54:17,934 713    [           main] DEBUG ntishell.dao.IUserDao.findById  - ==> Parameters: 41(Integer)
    2020-03-17 22:54:17,959 738    [           main] DEBUG ntishell.dao.IUserDao.findById  - <==      Total: 1
    com.mantishell.domain.User@282003e1
    2020-03-17 22:54:17,967 746    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@17695df3]
    2020-03-17 22:54:17,968 747    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@17695df3]
    2020-03-17 22:54:17,968 747    [           main] DEBUG source.pooled.PooledDataSource  - Returned connection 392781299 to pool.
    2020-03-17 22:54:17,972 751    [           main] DEBUG    com.mantishell.dao.IUserDao  - Cache Hit Ratio [com.mantishell.dao.IUserDao]: 0.5
    com.mantishell.domain.User@5606c0b
    
  • 相关阅读:
    python开发初识函数:函数定义,返回值,参数
    py基础2--列表,元祖,字典,集合,文件
    python中的urlencode与urldecode
    使用pymysql进行mysql数据库操作
    docker 命令
    docker镜象
    docker的安装
    JS中的prototype(原文地址:http://www.cnblogs.com/yjf512/archive/2011/06/03/2071914.html)
    linux远程复制和压缩文件的命令
    rosbag 初尝试
  • 原文地址:https://www.cnblogs.com/mantishell/p/12509456.html
Copyright © 2011-2022 走看看