zoukankan      html  css  js  c++  java
  • myBatis学习(9):一级缓存和二级缓存

    正如大多数持久层框架一样,MyBatis同样提供了一级缓存和二级缓存的支持

    1. MyBatis一级缓存基于PerpetualCache的HashMap本地缓存,其存储作用域为 Session,默认情况下,一级缓存是开启状态的。当 Session flush(); 或 close(); 之后,该Session中的所有 Cache 就将清空。

    2.MyBatis二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。

    3.对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。


    程序测试一级缓存

    usersMapper.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.entity.test009.usersMapper">

    <select id="myUsers" parameterType="int" resultType="Users">
    select * from users where id=#{id}
    </select>

    <select id="myUpdate" parameterType="Users">
    update users set username=#{username},password=#{password} where id=#{id}
    </select>

    </mapper>

    写一个获得一级缓存session的工具类:

    public class MyBatisUtils {
    
    	public static SqlSession mySession() throws Exception{
    	 
    		String resource = "conf.xml"; 
    		Reader reader = Resources.getResourceAsReader(resource); 
    		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
    		SqlSession session = factory.openSession(true); 
    		//session.clearCache();//删除缓存
    		return session;
    	}
    }
    

    测试程序代码

    ※第1种方法

    @Test
        public void cacheOne() throws Exception
        {
            SqlSession session = MyBatisUtils.mySession();
            String statement ="com.entity.test009.usersMapper.myUsers";
            
            users = session.selectOne(statement , 3);
            System.out.println(users);
            
            users = session.selectOne(statement , 3);
            System.out.println(users);
            //清理session的缓存
             session.clearCache(); 
            System.out.println("-----------------------------------");
            users = session.selectOne(statement , 3);
            System.out.println(users);
        }

    ※运行后的结果:

    2015-05-04 22:49:43,323 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==>  Preparing: select * from users where id=? 
    2015-05-04 22:49:43,361 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==> Parameters: 3(Integer)
    2015-05-04 22:49:43,387 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - <==      Total: 1
    Users [id=3, username=张三, password=123456, age=99, sex=0]
    Users [id=3, username=张三, password=123456, age=99, sex=0]
    --------------------- //session.clearCache();后又一次查询了数据库,并非从缓存中读取数据
    2015-05-04 22:49:43,388 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==>  Preparing: select * from users where id=? 
    2015-05-04 22:49:43,389 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==> Parameters: 3(Integer)
    2015-05-04 22:49:43,390 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - <==      Total: 1
    Users [id=3, username=张三, password=123456, age=99, sex=0]

    ※第2种方法

        @Test
        public void cacheOne() throws Exception
        {
            SqlSession session = MyBatisUtils.mySession();
            String statement ="com.entity.test009.usersMapper.myUsers";
            
            users = session.selectOne(statement , 3);
            System.out.println(users);
            
            users = session.selectOne(statement , 3);
            System.out.println(users);
            /**
             * 第2个方法,执行一个更新的操作
             */
            session.update("com.entity.test009.usersMapper.myUpdate", new Users(3, "张三", "123456", null, null));
            session.commit();
    System.out.println(
    "---------------------"); users = session.selectOne(statement , 3); System.out.println(users); }

    ※运行后的结果:

    2015-05-04 22:55:38,685 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==>  Preparing: select * from users where id=? 
    2015-05-04 22:55:38,724 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==> Parameters: 3(Integer)
    2015-05-04 22:55:38,747 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - <==      Total: 1
    Users [id=3, username=张三, password=123456, age=99, sex=0]
    Users [id=3, username=张三, password=123456, age=99, sex=0]
    2015-05-04 22:55:38,748 [main] DEBUG [com.entity.test009.usersMapper.myUpdate] - ==>  Preparing: update users set username=?,password=? where id=? 
    2015-05-04 22:55:38,749 [main] DEBUG [com.entity.test009.usersMapper.myUpdate] - ==> Parameters: 张三(String), 123456(String), 3(Integer)
    2015-05-04 22:55:38,749 [main] DEBUG [com.entity.test009.usersMapper.myUpdate] - <==    Updates: 1
    ---------------------//大家可以看出来,执行完更新后,一级缓存会被自动清理,然后下边又一次查询数据库
    2015-05-04 22:55:38,750 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==>  Preparing: select * from users where id=? 
    2015-05-04 22:55:38,750 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==> Parameters: 3(Integer)
    2015-05-04 22:55:38,751 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - <==      Total: 1
    Users [id=3, username=张三, password=123456, age=99, sex=0]

    ※第3种方法

        @Test
        public void cacheOne() throws Exception
        {
            SqlSession session = MyBatisUtils.mySession();
            String statement ="com.entity.test009.usersMapper.myUsers";
            
            users = session.selectOne(statement , 3);
            System.out.println(users);
            
            users = session.selectOne(statement , 3);
            System.out.println(users);
    
            /**
             * 第3个方法,并非同一个session对象。关闭session后,重新再开一个session2。这个时候和刚才的不一样,所以就不会用session刚才的缓存了
             */
            session.close();
            SqlSession session2 = MyBatisUtils.mySession();
            
            System.out.println("---------------------");
            users = session2.selectOne(statement , 3);
            System.out.println(users);
        }

    ※运行后的结果:

    2015-05-04 23:06:25,518 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==>  Preparing: select * from users where id=? 
    2015-05-04 23:06:25,557 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==> Parameters: 3(Integer)
    2015-05-04 23:06:25,580 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - <==      Total: 1
    Users [id=3, username=张三, password=123456, age=99, sex=0]
    Users [id=3, username=张三, password=123456, age=99, sex=0]
    ---------------------//重新获取session,这个session2重新从数据库查询一条数据出来
    2015-05-04 23:06:25,794 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==>  Preparing: select * from users where id=? 
    2015-05-04 23:06:25,794 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==> Parameters: 3(Integer)
    2015-05-04 23:06:25,795 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - <==      Total: 1
    Users [id=3, username=张三, password=123456, age=99, sex=0]

    二级缓存测试(默认关闭状态)

    首先在usersMapper.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.entity.test009.usersMapper">
     <cache/> 
    <select id="myUsers" parameterType="int" resultType="Users">
     select * from users where id=#{id}
    </select>
    
    <select id="myUpdate" parameterType="Users">
     update users set username=#{username},password=#{password} where id=#{id}
    </select>
     
    </mapper> 

    然后新建一个创建工厂的工具类,返回一个factory,这样创建出来的session就不一样。

    public class CopyOfMyBatisUtils {
    
    	public static SqlSessionFactory factory() throws Exception{
    	 
    		String resource = "conf.xml"; 
    		Reader reader = Resources.getResourceAsReader(resource); 
    		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
    		return factory;
    	}
    }
    

    测试代码:

    @Test
        public void cacheTwo() throws Exception
        {
            
            String statement ="com.entity.test009.usersMapper.myUsers";
            
            SqlSessionFactory factory = CopyOfMyBatisUtils.factory();
            SqlSession session1 = factory.openSession();
            SqlSession session2 = factory.openSession();
            
            users = session1.selectOne(statement , 6);
            session1.commit();//需要提交事物,否则二级缓存无效
            System.out.println(users);
            
            System.out.println("****************************");
            
             
            users = session1.selectOne(statement , 6);
            session2.commit();
            System.out.println(users);
         
        }

    运行结果:

    2015-05-04 23:45:21,750 [main] DEBUG [com.entity.test009.usersMapper] - Cache Hit Ratio [com.entity.test009.usersMapper]: 0.0
    2015-05-04 23:45:22,035 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==>  Preparing: select * from users where id=? 
    2015-05-04 23:45:22,079 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - ==> Parameters: 6(Integer)
    2015-05-04 23:45:22,100 [main] DEBUG [com.entity.test009.usersMapper.myUsers] - <==      Total: 1
    Users [id=6, username=张3, password=654321, age=99, sex=0]
    ****************************
    2015-05-04 23:45:22,109 [main] DEBUG [com.entity.test009.usersMapper] - Cache Hit Ratio 缓存命中率  [com.entity.test009.usersMapper]: 0.5 百分比
    Users [id=6, username=张3, password=654321, age=99, sex=0]

    补充说明:

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

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

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

    根据时间表(比如no  Flush  Interval,没有刷新间隔),缓存不会以任何时间顺序来刷新。 

    缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用。 

    缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改

    <cache 
    
    eviction="FIFO"  //回收策略为先进先出
    
    flushInterval="60000" //自动刷新时间60s
    
    size="512" //最多缓存512个引用对象
    
    readOnly="true"  //只读
    />
  • 相关阅读:
    ASCII 32个控制字符含义
    MFC中获取指定打印机的打印队列的方法
    某品牌led报文信息分析
    SQL Server 企业版没有 Management Studio管理工具 无法安装工作站组件 的解决方法(无需卸载重装)
    xla文件修改办法
    关于ALILIB
    编译器如何根据头文件来找到相应实现的cpp文件?
    C#调用C++接口提示找不到指定的模块解决方法,本机正常
    DataGridView中实现右击选中当前行功能,并通过ContextMenuStrip获取当前行
    C#递归获取文件列表
  • 原文地址:https://www.cnblogs.com/koal/p/4477971.html
Copyright © 2011-2022 走看看