精华内容
下载资源
问答
  • 一级缓存原理
    千次阅读
    2015-06-30 16:52:34
    查询缓存

    1.什么是查询缓存
    mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
    mybaits提供一级缓存,和二级缓存。

    缓存模式图如图



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

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

    为什么要用缓存?
    如果缓存中有数据就不用从数据库中获取,大大提高系统性能。

    2.一级缓存
    2.1一级缓存工作原理

    如图



    第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。
    得到用户信息,将用户信息存储到一级缓存中。

    如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

    第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

    2.2一级缓存测试
    mybatis默认支持一级缓存,不需要在配置文件去配置。

    按照上边一级缓存原理步骤去测试。

    测试1:
    //测试一级缓存
    @Test
    public void testCache1() throws Exception{
    	SqlSession sqlSession = sqlSessionFactory.openSession();//创建代理对象
    	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    	
    	//下边查询使用一个SqlSession
    	//第一次发起请求,查询id为1的用户
    	User user1 = userMapper.findUserById(1);
    	System.out.println(user1.getUsername());
    
    	//第二次发起请求,查询id为1的用户
    	User user2 = userMapper.findUserById(1);
    	System.out.println(user2.getUsername());
    	
    	sqlSession.close();
    	
    }

    测试结果和输出日志:
    DEBUG [main] - Opening JDBC Connection
    DEBUG [main] - Created connection 19140890.
    DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.Connection@124111a]
    DEBUG [main] - ==>  Preparing: SELECT * FROM USER WHERE id=? 
    DEBUG [main] - ==> Parameters: 1(Integer)
    DEBUG [main] - <==      Total: 1
    张三
    张三
    DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.Connection@124111a]
    DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.Connection@124111a]
    DEBUG [main] - Returned connection 19140890 to pool.

    可以看到第二次取user2的时候没有发出sql查询,说明调用了一级缓存

    接下来测试看看在中间执行了增删改查的时候会不会清空一级缓存
    //测试一级缓存
    @Test
    public void testCache1() throws Exception{
    	SqlSession sqlSession = sqlSessionFactory.openSession();//创建代理对象
    	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    	
    	//下边查询使用一个SqlSession
    	//第一次发起请求,查询id为1的用户
    	User user1 = userMapper.findUserById(1);
    	System.out.println(user1.getUsername());
    	
    	/*如果sqlSession去执行commit操作(执行插入、更新、删除),
    	 * 清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
    	 */
    	
    	//更新user1的信息
    	user1.setUsername("测试用户22");
    	userMapper.updateUser(user1);
    	//执行commit操作去清空缓存
    	sqlSession.commit();
    	
    	//第二次发起请求,查询id为1的用户
    	User user2 = userMapper.findUserById(1);
    	System.out.println(user2.getUsername());
    	
    	sqlSession.close();
    	
    }
    

    测试结果和输出日志:
    DEBUG [main] - Opening JDBC Connection
    DEBUG [main] - Created connection 6778431.
    DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.Connection@676e3f]
    DEBUG [main] - ==>  Preparing: SELECT * FROM USER WHERE id=? 
    DEBUG [main] - ==> Parameters: 1(Integer)
    DEBUG [main] - <==      Total: 1
    张三
    DEBUG [main] - ==>  Preparing: update user set username=?,birthday=?,sex=?,address=? where id=? 
    DEBUG [main] - ==> Parameters: 测试用户2(String), 2015-06-07(Date), 男(String), 河南焦作(String), 1(Integer)
    DEBUG [main] - <==    Updates: 1
    DEBUG [main] - Committing JDBC Connection [com.mysql.jdbc.Connection@676e3f]
    DEBUG [main] - ==>  Preparing: SELECT * FROM USER WHERE id=? 
    DEBUG [main] - ==> Parameters: 1(Integer)
    DEBUG [main] - <==      Total: 1
    测试用户2
    DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.Connection@676e3f]
    DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.Connection@676e3f]
    DEBUG [main] - Returned connection 6778431 to pool.

    发现第二次取数据时发出了sql请求,说明执行增删改查的时候会清空一级缓存
    12:06 2015/6/21
    2.3一级缓存应用

    正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
    一个service方法中包括 很多mapper方法调用。


    service{
    //开始执行时,开启事务,创建SqlSession对象
    //第一次调用mapper的方法findUserById(1)

    //第二次调用mapper的方法findUserById(1),从一级缓存中取数据
    //方法结束,sqlSession关闭
    }



    如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为service方法结束,sqlSession就关闭,一级缓存就清空。这个时候就需要使用二级缓存,详情看下一篇总结

    转载请注明出处:http://blog.csdn.net/acmman/article/details/46696265

    更多相关内容
  • 程序中为什么使用缓存?... 一级缓存:它指的是Mybatis中sqlSession对象的缓存,当我们执行查询以后,查询的结果会同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当我们再次查询同样的数据

    程序中为什么使用缓存?
       实际上适用于缓存的数据:经常查询并且不经常改变的,并且的数据的正确与否对最终结果影响不大的、不适用于缓存的数据:经常改变的数据,数据的正确与否对最终
    结果影响很大的。
    Mybatis中的一级缓存和二级缓存到底缓存了什么,缓存了以后又有什么效果,缓存的数据什么时候会被清空?
      一级缓存:它指的是Mybatis中sqlSession对象的缓存,当我们执行查询以后,查询的结果会同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当我们再次查询同样的数据,mybatis会
    先去sqlsession中查询是否有,的话直接拿出来用,当SqlSession对象消失时,mybatis的一级缓存也就消失了,同时一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除、commit(),close等
    方法时,就会清空一级缓存。
      二级缓存:他值得是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享其缓存,但是其中缓存的是数据而不是对象,所以从二级缓存再次查询出得结果的对象与
    第一次存入的对象是不一样的。
      通过简单的例子来加深理解一级缓存和二级缓存。
    一级缓存
    1.用户类

    public class User implements Serializable{
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
        
        get和set方法省略.....
    }
    

    2.Dao层

    public interface UserDao {
      /**
       * 查询所有的用户
       *
       * @return
       */
      List<User> findAll();
      /**
       * 根据Id查询用户
       *
       * @return
       */
      User findById(Integer id);
      /**
       * 更新用户
       * @param user
       */
      void updateUser(User user);
    

    3.UserDao.xml映射文件

    <mapper namespace="com.example.dao.UserDao">
        <select id="findAll" resultType="com.example.domain.User">
            SELECT * FROM USER;
        </select>
        <select id="findById" resultType="com.example.domain.User" parameterType="INT">
            SELECT * FROM  USER  WHERE ID = #{ID}
        </select>
        <update id="updateUser" parameterType="com.example.domain.User">
            update USER
            <set>
                <if test="username != null">username=#{username},</if>
                <if test="password != null">birthday=#{birthday},</if>
                <if test="sex != null">sex=#{sex},</if>
                <if test="address != null">address=#{address},</if>
            </set>
            where id=#{id}
        </update>
    </mapper>
    

    在以上三步中这是mybatis的单表操作,下面通过根据用户ID查询用户的操作来观察一级缓存生效与否的区别

    4.测试
    (1) 命中一级缓存的情况
    测试代码:

    @Test
        public void findByIdTest(){
            session = factory.openSession();
            userDao = session.getMapper(UserDao.class);
            //第一次获取该用户
            User user1 = userDao.findById(45);
            System.out.println(user1);
            第二次获取该用户
            User user2 = userDao.findById(45);
            System.out.println(user2);
            System.out.println(user1 == user2);
            session.close();
        }  
    

    测试结果:
    在这里插入图片描述
    (2)对SqlSession进行清除缓存的操作,即清楚一级缓存,然后再次进行测试。

    @Test
        public void findByIdTest(){
            session = factory.openSession();
            userDao = session.getMapper(UserDao.class);
            User user1 = userDao.findById(45);
            System.out.println(user1);
     //       session.commit(); 调用SqlSession的commit方法清空缓存
    
            user1.setUsername("更新用户");
            user1.setAddress("更新地址");
            userDao.updateUser(user1);//通过更新SqlSession清空缓存
            User user2 = userDao.findById(45);
            System.out.println(user2);
            System.out.println(user1 == user2);
            session.close();
        }
    

    清空缓存的操作很多,可以都试试。测试结果:
    在这里插入图片描述
     二级缓存  
      再看一下Mybatis二级缓存是如何使用的,第一步让Mybatis框架支持二级缓存(在Mybatis的主配置文件中配置),第二步让当前的映射文件支持二级缓存(在Dao.xml映射文件中配置),第三步让当前的方法支持二级缓存(在标签中配置)。根据这个步骤将上面的查询用户的接口通过配置改造为可以支持二级缓存的方法。
    1.配置Mybatis框架支持二级缓存

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

    2.配置UserDao.xml支持二级缓存

     <cache/>
    

    3.配置查询的方法支持二级缓存

    <select id="findById" resultType="com.example.domain.User" parameterType="INT" useCache="true">
            SELECT * FROM  USER  WHERE ID = #{ID}
    </select>
    

    4.测试

    @Test
        public void findByIdTest(){
            //第一次查询 并更新二级缓存
            SqlSession session1 = factory.openSession();
            UserDao userDao1 = session1.getMapper(UserDao.class);
            User user1 = userDao1.findById(45);
            System.out.println(user1);
            session1.commit(); //commit()方法提交二级缓存 同时清空一级缓存
            session1.close();//
    
    //        user1.setUsername("更新用户");
    //        user1.setAddress("更新地址");
    //        userDao.updateUser(user1);//通过更新SqlSession清空缓存
            //第二次查找命中二级缓存
            SqlSession session2 = factory.openSession();
            UserDao userDao2 = session2.getMapper(UserDao.class);
            User user2 = userDao2.findById(45);
            session2.commit(); //commit()方法提交二级缓存 同时清空一级缓存
            session2.close();//
            System.out.println(user2);
            System.out.println(user1 == user2);
        }
    

    测试结果:
    在这里插入图片描述
    总结:mybatis的的一级缓存是SqlSession级别的缓存,一级缓存缓存的是对象,当SqlSession提交、关闭以及其他的更新数据库的操作发生后,一级缓存就会清空。二级缓存是SqlSessionFactory级别的缓存,同一个SqlSessionFactory产生的SqlSession都共享一个二级缓存,二级缓存中存储的是数据,当命中二级缓存时,通过存储的数据构造对象返回。查询数据的时候,查询的流程是二级缓存>一级缓存>数据库。

    展开全文
  • 主要给大家深入的介绍了关于MyBatis中一级缓存与二级缓存的相关资料,文中详细介绍MyBatis中一级缓存与二级缓存的工作原理及使用,对大家具有一定的参考性学习价值,需要的朋友们下面来一起看看吧。
  • 一、前言MyBatis将数据缓存设计成两级结构,分为一级缓存、二级缓存:一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存。一级缓存是MyBatis内部实现的一个特性,...

    一、前言

    MyBatis将数据缓存设计成两级结构,分为一级缓存、二级缓存
    一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存。一级缓存是MyBatis内部实现的一个特性,用户不能配置,默认情况下自动支持的缓存,用户没有定制它的权利(不过这也不是绝对的,可以通过开发插件对它进行修改);
    每当我们使用MyBatis开启一次和数据库的会话,MyBatis会创建出一个SqlSession对象表示一次数据库会话。在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。
    为了解决这一问题,减少资源的浪费,MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候,如果判断先前有个完全一样的查询,会直接从缓存中直接将结果取出,返回给用户,不需要再进行一次数据库查询了。

    如下图所示,MyBatis会在一次会话的表示—-一个SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否在缓存中,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。


    这一节,我们将简单的说说什么是一级缓存以及什么情况下会导致一级缓存失效?

    二、案例

    创建一个新的Maven工程MyBatisPrimaryCache,工程结构目录如下


    在测试类MyBatis中增加测试方法testPrimaryCache


    打印查看一下控制台

    2017-08-17 21:08:20,836 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==>  Preparing: select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id = ? 
    2017-08-17 21:08:20,888 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==> Parameters: 1(Integer)
    2017-08-17 21:08:20,924 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] <==      Total: 1
    Emp [id=1, empName=queen3aasd21, empEmail=queen123@sina.com, deptId=1]
    Emp [id=1, empName=queen3aasd21, empEmail=queen123@sina.com, deptId=1]
    true

    从控制台我们可以看到,即便Java代码中查询Emp信息,写了两段代码,但是实际上去后台数据库查询只做了一次SQL调用,第二次查询并没有去数据库查询,第二次获取的数据与第一次一样,它就直接从缓存中拿了数据。

    如上我们简单的体验了一下一级缓存的存在

    一级缓存我们也称作SqlSession级别的缓存,一级缓存默认就是开启的。既然是SqlSession级别的缓存,那就说明每个SqlSession对象拥有自己的一份数据,每个SqlSession之间是不能共享缓存的。但是每个独立的SqlSession缓存也有失效的时候。

    下面我们通过案例看看哪些情况会导致一级缓存失效

    ①SqlSession不同

    上面第一个测试案例,我们查询emp01和emp02都是使用的同一个mapper对象,如果mpper不是同一个会是什么情况,修改代码如下:


    测试打印,查看一下控制台

    2017-08-17 21:28:41,663 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==>  Preparing: select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id = ? 
    2017-08-17 21:28:41,731 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==> Parameters: 1(Integer)
    2017-08-17 21:28:41,774 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] <==      Total: 1
    Emp [id=1, empName=queen3aasd21, empEmail=queen123@sina.com, deptId=1]
    
    2017-08-17 21:28:41,786 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==>  Preparing: select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id = ? 
    2017-08-17 21:28:41,787 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==> Parameters: 1(Integer)
    2017-08-17 21:28:41,789 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] <==      Total: 1
    Emp [id=1, empName=queen3aasd21, empEmail=queen123@sina.com, deptId=1]
    false

    如上,我们发现控制台打印了两段SQL,第二次查询取数据库重新获取了数据,封装成了一个新的对象,emp01==emp02 为false,说明不是同一个对象。一级缓存失效。

    ②SqlSession相同,但是查询条件不一样(当前一级缓存中还没有数据)


    必然上面查询会发出两条SQL,查询2号员工时,因为本来就是第一次查询,所以不可能存在于缓存中的数据,需要调用数据库查询数据。

    ③SqlSession相同,两次查询之间增加了增删改操作


    测试打印,查看一下控制台如下:

    2017-08-17 21:45:12,885 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==>  Preparing: select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id = ? 
    2017-08-17 21:45:12,960 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==> Parameters: 1(Integer)
    2017-08-17 21:45:13,000 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] <==      Total: 1
    Emp [id=1, empName=queen3aasd21, empEmail=queen123@sina.com, deptId=1]
    2017-08-17 21:45:13,052 [main] [com.queen.mybatis.mapper.EmpMapper.updateEmp]-[DEBUG] ==>  Preparing: update t_emp SET emp_name=?, emp_email=? where id=? 
    2017-08-17 21:45:13,053 [main] [com.queen.mybatis.mapper.EmpMapper.updateEmp]-[DEBUG] ==> Parameters: tom123(String), tom123@sina.com(String), 3(Integer)
    2017-08-17 21:45:13,053 [main] [com.queen.mybatis.mapper.EmpMapper.updateEmp]-[DEBUG] <==    Updates: 1
    =====数据修改成功!======
    2017-08-17 21:45:13,054 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==>  Preparing: select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id = ? 
    2017-08-17 21:45:13,054 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==> Parameters: 1(Integer)
    2017-08-17 21:45:13,056 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] <==      Total: 1
    Emp [id=1, empName=queen3aasd21, empEmail=queen123@sina.com, deptId=1]
    false

    如上所述,一级缓存失效了,虽然两次都是查询的同一条数据,但是却发了两次SQL,封装了两次对象且不是同一个对象。所以这种情况也会导致缓存失效。这种情况也比较容易理解,因为你在做修改的时候,可能就会修改到这条数据,当你修改了这条数据后,难道我还要去缓存中拿数据吗?当然是不行的。只要数据库有变化,就要再次去数据库查询数据。

    ④SqlSession相同,但是我们手动清除了一级缓存(缓存清空)


    测试打印,查看一下控制台如下:

    2017-08-17 21:56:21,619 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==>  Preparing: select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id = ? 
    2017-08-17 21:56:21,680 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==> Parameters: 1(Integer)
    2017-08-17 21:56:21,723 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] <==      Total: 1
    Emp [id=1, empName=queen3aasd21, empEmail=queen123@sina.com, deptId=1]
    2017-08-17 21:56:21,724 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==>  Preparing: select id,emp_name empName,emp_email empEmail, dept_id deptId from t_emp where id = ? 
    2017-08-17 21:56:21,724 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] ==> Parameters: 1(Integer)
    2017-08-17 21:56:21,726 [main] [com.queen.mybatis.mapper.EmpMapper.findEmpById]-[DEBUG] <==      Total: 1
    Emp [id=1, empName=queen3aasd21, empEmail=queen123@sina.com, deptId=1]
    false

    我们发现这个时候也一样,缓存也失效了,第二次查询还是去数据库重新查询了一遍数据。因为缓存中已经没有数据了。


    =======欢迎大家拍砖,小手一抖,多多点赞哟!=======

    版权声明:本文为博主原创文章,允许转载,但转载必须标明出处。


    展开全文
  • Mybatis 中的一级缓存与二级缓存

    千次阅读 2022-01-19 23:57:32
    Mybatis 中的一级缓存与二级缓存

    一,Mybatis中为什么要有缓存

      缓存的意义是将用户经常查询的数据放入缓存(内存)中去,用户去查询数据的时候就不需要从磁盘(关系型数据库)中查询,直接从缓存中查询,从而提高了查询效率,解决了高并发中系统的性能问题。Mybatis中提供一级缓存与二级缓存。
    在这里插入图片描述
      Mybatis的一级缓存是一个SqlSession级别的缓存,只能访问自己的一级缓存数据,而二级缓存是Mapper级别的缓存,是跨SqlSession的,不同的SqlSession是可以共享缓存数据的。
    在这里插入图片描述

    二,一级缓存

      Mybatis 一级缓存原理:
    在这里插入图片描述
      第一次发出查询请求,sql 查询的结果写入SqlSession的一级缓存当中,缓存使用的数据结构是一个map<key, value>

    1. key : hashcode + sql + sql输入参数 + 输出参数 (sql的唯一标识)
    2. value : 用户信息

      同一个SqlSession再次发出相同的sql,就会从缓存中读取而不走数据库,如果两次操作之间出现commit(修改、输出、添加)操作,那么本SqlSession中一级缓存区域全部清空,下次再去缓存中查不到所以要从数据库中查询,从数据库再写入一级缓存。

    @Test
    public void createTable(){
        SqlSession sqlSession = DBUtil.getSqlSession();
        List<Map<String, Object>> list1 = sqlSession.selectList("com.snow.xml.SnowOracle.getEmployeeByName", "周康");
        System.out.println(list);
    
        List<Map<String, Object>> list2 = sqlSession.selectList("com.snow.xml.SnowOracle.getEmployeeByName", "周康");
        System.out.println(list2);
    }
    

      在数据库中有一张Employee表,里面有一条数据,通过selectList的方法查询,结果如下[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=36, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]
    在这里插入图片描述
      此时,手动修改数据库该人的年龄,手动修改为35,然后保存
    在这里插入图片描述
      此时,在运行代码,查看list2的值,两次结果一致,都是36 并非 35,说明第二次相同的查询走的是SqlSession中的一级缓存。
    在这里插入图片描述
      Mybatis 中一级缓存需要注意的点 :

    1. Mybatis 中一级缓存是默认开启的,不需要手动配置。
    2. MybatisSpring 整合后进行 mapper 代理开发后,不支持一级缓存。MybatisSpring 整合,Spring 按照 mapper 的模板去生成 mapper 代理对象,模板中在最后会统一关闭 SqlSession

    三、二级缓存

      Mybatis二级缓存原理:
    在这里插入图片描述
      二级缓存的范围是mapper级别(mapper同一个命名空间),mapper以命名空间为单位创建缓存数据结构,结构是map<key, value>。每次查询前看是否开启了二级缓存,如果开启则从二级缓存的数据结构中取缓存数据,如果二级缓存中没有取到,再从一级缓存中取,如果一级缓存也没有,那就从数据库中查询。

    1. 二级缓存配置

      需要在Mybatis的配置文件中<settings>标签中配置二级缓存:

    <settings>
        <setting name="cacheEnabled" value="true"/> <!--Mybatis的二级缓存配置-->
    </settings>
    

      Mybatis的二级缓存的范围是mapper级别的,因此我们mapper如果想要使用二级缓存,还需要在对应的映射文件中配置<cache>标签

    <mapper namespace="com.snow.xml.SnowOracle">
        <cache></cache> <!--Mybatis的二级缓存配置-->
    </mapper>
    

    测试:

    @Test
    public void test(){
        SqlSession sqlSession1 = DBUtil.getSqlSession();
        List<Map<String, Object>> list1 = sqlSession1.selectList("getEmployeeByName", "周康");
        System.out.println("list1=" + list1);
        sqlSession1.commit();
        sqlSession1.close();
        DBUtil.closeSqlsession();
    
        SqlSession sqlSession2 = DBUtil.getSqlSession();
        List<Map<String, Object>> list2 = sqlSession2.selectList("getEmployeeByName", "周康");
        System.out.println("list2=" + list2);
        sqlSession2.commit();
        sqlSession2.close();
    }
    

    在SqlSession2 创建处打断点,观看此时输出:list1=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=35, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]
    在这里插入图片描述
    此时去修改数据库中周康此人的年龄,改为37提交,代码继续往下执行,会看到SqlSession2 与SqlSession1 是两个不同的SqlSession,观看此时输出:list2=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=35, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]
    在这里插入图片描述
    在这里插入图片描述
    两次结果一致,均为35岁,说明SqlSession2 的查询没有走数据库,而是用了Mybatis的二级缓存,从里面拿到的数据,虽然是两个不同的SqlSession,但是二级缓存是mapper级别的,SqlSession1 只执行了查询操作没有增改删,所以不会清空二级缓存中的数据。

    此处如果关闭了二级缓存的配置,查询出来的结果会是实时的,因为一级缓存默认开启,一级缓存的作用是SqlSession级别的,不同的SqlSession缓存数据不共享。这里就不演示一级缓存效果了。

    1. 禁用二级缓存

      有些情况下,我们需要打开二级缓存的配置,但是某个sql语句的查询变化频率较高,则需要针对该sql禁用二级缓存。在xml中statement中设置useCache=false 则可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认是true(使用二级缓存)

    <select id="getEmployeeByName" parameterType="string" resultType="java.util.LinkedHashMap" useCache="false">
        SELECT E.ID, E.EMPNAME, E.AGE, GB01.DMGRP, E.BIRTHDATE, E.SALARY, E.ADDRESS, GB02.DMGRP AS GRADE
            FROM EMPLOYEE E LEFT JOIN GB01 ON E.SEX = GB01.ID LEFT JOIN GB02 ON E.GRADE = GB02.ID
        WHERE E.EMPNAME = #{name}
    </select>
    

    测试:
    操作与上面一样,SqlSession2处打断点,更改数据库中该人的年龄,查看两次输出结果。
    在这里插入图片描述
    在这里插入图片描述
    list1=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=37, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]
    list2=[{ID=70DD7D10-9FC6-4B79-ADAF-8B408DE1E048, EMPNAME=周康, AGE=35, DMGRP=男, BIRTHDATE=1987-07-31 00:00:00.0, SALARY=17000, ADDRESS=湖南长沙, GRADE=高级架构师}]

    可以看到操作虽然与第一次一样,可结果却变了,虽然二级缓存中有周康该人的信息,但是SqlSession2 还是从数据库中查询到了此人最新的数据,因为我们禁用了二级缓存。useCache=false

    1. 增删改的二级缓存

      二级缓存其实大部分都是为查询服务的,对于它们而言,如果我们缓存的数据不是最新的那么就会读到脏数据了。增删改之后之所以二级缓存会被清空是因为它们有一个默认的flushCache=true,默认在sql结束后刷新二级缓存,可以通过修改配置值达到不刷新缓存的目的(不建议使用)。

    <update id="updateAgeByName" parameterType="string" flushCache="false">
        UPDATE EMPLOYEE SET AGE = '40' WHERE EMPNAME = #{EMPNAME}
    </update>
    

    四、了解Mybatis缓存的一些参数

      mybatis 的cache 参数只适用于mybatis 维护缓存。

    flushInterval : 刷新间隔,可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式时间段,默认情况是不设置,也就是没有刷新间隔,缓存仅仅在调用语句时刷新。

    size : 引用数目,可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目默认值为1024。

    readOnly : 只读属性,可被设置为true or false,只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改,这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这样会导致效率慢一些,但是安全,默认值为false。

    <cache eviction="FIFO" flushInterval="6000" size="512" readOnly="true" />
    

      这样的二级缓存配置,创建了一个FIFO的缓存,并且每隔60秒刷新,存数结果对象或列表的512个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。

    默认的回收策略有(默认为LRU):

    1. LRU:最近最少使用的,移除最长时间不被使用的对象。
    2. FIFO:先进先出,俺对象进入缓存的顺序来移除它们。
    3. SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象。
    4. WEAK:弱引用,更积极地移除给予垃圾回收器状态和弱引用规则的对象。
    展开全文
  • 今天小编就为大家分享篇关于Android三级缓存原理讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
  • Mybatis一级缓存失效原因详解

    千次阅读 2020-12-23 17:50:01
    1、mybatis整合spring,一级缓存会失效,mybatis会在每次查询之后自动关闭sqlSession。 2、二级缓存多线程共享,开启方式(注解)@CacheNamespace或者在xml文件中开启,开启方式为<settingname='cacheEnabled'...
  • Mybatis二级缓存原理

    千次阅读 2018-12-12 12:32:57
    最近看了下Mybatis的源码,分析了二级缓存的实现方式,在这里把他记下来。虽然这不复杂,对这方面的博客也有很多,写的也很好。但我坚信看懂了是其,能够教别人或者描述清楚记下来才能真正的掌握。曹金桂 cao_...
  • 1 MyBatis的一级缓存是基于SqlSession级别的,也就是说某个SqlSession进行某个查询操作后会将该结果暂时缓存起来,而后在所有的SqlSession没有对该表进行插入、修改、删除操作的情况下,当这个SqlSession再次发起此...
  • 一级缓存2.1 一级缓存的命中场景2.2 触发清空一级缓存2.3 一级缓存源码分析3 二级缓存3.1 二级缓存的设计3.2 二级缓存的使用3.3 二级缓存的命中场景3.4 二级缓存源码分析3.4.1 query查询操作。3.4.2 commit提交操作...
  • mybatis二级缓存架构原理

    千次阅读 2022-03-14 16:06:05
    一级缓存 与springboot集成时一级缓存不生效原因以及解决方案 如何解决这个问题? 要知道如何解决这个问题, 二级缓存 为什么mybatis默认不开启二级缓存? 不推荐使用。 ...
  • Glide源码分析以及三级缓存原理

    千次阅读 2022-02-12 16:10:34
    Glide是Android端开源图片加载库,能够帮助我们下载、缓存、展示多种格式图片。也是现在主流图片加载框架之。源码内部究竟是如何实现的呢?讲解主流程,简略分析。 用法如下: Glide.with(context).load(url)....
  • 关于mybatis里面的一级缓存: mybatis里面的一级缓存和二级缓存实际上和hibernate里面的差别不大。 一级缓存其实通俗地来讲就是,在sqlsession里面创建一个本地缓存,然后第二次进行相同的查询时候,就不会到...
  • MyBatis一级缓存和二级缓存

    千次阅读 2022-04-03 20:36:19
    Mybatis缓存
  • mybatis的一级缓存实现原理

    千次阅读 2015-10-23 16:53:03
    0.写在前面  MyBatis是一个简单,小巧但功能非常强大...本文的目的则是向读者详细介绍MyBatis的一级缓存,深入源码,解析MyBatis一级缓存的实现原理,并且针对一级缓存的特点提出了在实际使用过程中应该注意的事项。
  • Mybatis缓存(四)-二级缓存实现原理

    千次阅读 2021-09-07 19:50:22
    级缓存实现原理概述CachingExecutor类TransactionalCacheManagerCachingExecutor#queryCachingExecutor#update 概述 MyBatis二级缓存在默认情况下是关闭的,因此需要通过设置cacheEnabled参数值为true来开启二...
  • 一级缓存和二级缓存的理解

    千次阅读 2020-07-18 10:39:00
    CPU是块超大规模的集成电路,是台计算机的运算核心(Core)和控制核心(Control Unit); CPU功能主要是解释计算机指令以及处理计算机软件中的数据; 中央处理器主要包括运算器(算术逻辑运算单元,...
  • hibernate二级缓存)二级缓存的实现原理 在前面我们将过hibernate二级缓存类似于个插件,将缓存的具体实现分离,缓存的具体实现是通过hibernate.cache.region.factory_class参数配置指定。 1. hibernate二...
  • 大家都知道CPU缓存很重要,但对于缓存的具体细分却知之甚少,本文只要是关于CPU缓存的介绍,并着重描述了一级缓存、二级缓存、三级缓存区别方法。 CPU缓存 CPU缓存(Cache Memory)是位于CPU与内存之间的临时存储器...
  • mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache
  • 缓存:将相同查询条件的sql语句执行遍后所得到的结果存在内存或者某种缓存介质当中,当下次遇到一模一样的查询sql时候不在执行sql与数据库交互,而是直接从缓存中获取结果,减少服务器的压力; myb...
  • 版本:mybatis-3.5.4 mybatis的单元测试采用HSQLDB ... 缓存是MyBatis中非常重要的特性。...MyBatis提供了一级缓存和二级缓存,其中一级缓存基于SqlSession实现,而二级缓存基于Mapper实现。 MyBa.
  • 3.一级缓存案例详解 3.1 首先写一个实体Bean 3.2 dao接口、对应的mapper映射文件 3.3 mybatis配置文件、工具类 3.4 测试方法 3.4.1 同一个会话对象查询同一个数据 3.4.2 同一个会话对象查询两个不同的数据 ...
  • MyBatis中的一级缓存和二级缓存介绍

    万次阅读 多人点赞 2017-06-13 20:07:22
    先说缓存,合理使用缓存是优化...一级缓存 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。也
  • Hibernate一级缓存和二级缓存详解

    万次阅读 多人点赞 2014-10-14 09:02:38
    一、一级缓存二级缓存的概念解释 (1)一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个 session(一定要同一个session)又做了同一个操作,...
  • Mybatis 一级缓存和二级缓存

    千次阅读 2021-01-15 01:01:56
    本文的目的则是向读者详细介绍MyBatis的一级缓存,深入源码,解析MyBatis一级缓存的实现原理,并且针对一级缓存的特点提出了在实际使用过程中应该注意的事项。 一级缓存 Mybatis的一级缓存是指SQLSession,一级缓存...
  • Mybatis的一级缓存和二级缓存详解

    千次阅读 多人点赞 2018-11-19 19:11:59
    注:本笔记是根据尚硅谷的MyBatis视频记录的 对于任何一个持久层框架,都有缓存机制;... 两个关于mybatis缓存额外的链接: ...关于Mybatis的一级缓存和二级缓存执行顺序具体可参考:Mybatis的一级缓存和二级缓存执行...
  • MyBatis实战(5)缓存机制(一级缓存、二级缓存)

    千次阅读 多人点赞 2019-11-30 09:49:01
    这篇博客对Mybatis中的一级缓存和二级缓存做了比较详细的阐述,并有完整的代码实现。
  • Mybatis 实现原理级缓存

    千次阅读 2018-10-15 15:19:20
    本片文章讲述的是Mybatis是如何无感知的让用户使用到级缓存,以及级缓存的实现细节和实现原理。 结论:Mybatis 下文通过代码DEMO的展示, 以及源码的解说介绍JDK动态代理, 和Mybatis对其的应用。 ...
  • hibernate二级缓存(一)一级缓存与二级缓存 1.hibernate一级缓存 hibernate的一级缓存是session级别的缓存,一级缓存hibernate默认启用且不能被卸载,一个事务内有效。 特点: 使用一级缓存的目的是为了...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 249,994
精华内容 99,997
关键字:

一级缓存原理