• mybatis的缓存机制


    简介:

      Mybatis是我们常用到的数据层访问框架,在通常的开发过程中,我们一般是使用它的默认的缓存配置。这里的话我们简单的分析一下Mybatis的缓存机制。

    Mybatis的一级缓存:

      在程序的运行过程中,我们有可能在一次的数据库会话中,执行多次查询条件完全相同的查询语句,这时候Mybatis中的一级缓存就排上了用场,如果是执行相同的SQL语句,会避免直接对数据库来进行操作,而是从一级缓存中来查询数据,这样可以在一定程度上提高查询的性能。

      一级缓存的应用范围是在SqlSession中,当用户发起松球的时候,Mybatis会根据当前执行的语句生成映射声明(MappedStatement),然后在Local Cache中进行查询,如果有缓存中有数据的数就直接返回查询的结果给用户。如果缓存中没有的话,查询数据库,并且将结果写入到Local Cache中,最后将结果返回个用户。下面做一个基本的案例展示。

      User类的代码如下:

     1 package com.buwei.entity;
     2 
     3 /**
     4  * @author buwei
     5  * @date 2018/12/20 12:33
     6  */
     7 public class User {
     8     private int id;
     9     private String name;
    10     private String password;
    11     //   省略getter和setter方法
    12 }

      接口UserMapper和对应的映射文件UserMapper.xml的代码如下:

     1 package com.buwei.mapper;
     2 
     3 import com.buwei.entity.User;
     4 import java.util.List;
     5 /**
     6  * @author buwei
     7  * @date 2018/12/20 12:34
     8  */
     9 public interface UserMapper {
    10     /**
    11      * 查询所有
    12      * @return 返回所有的查询数据
    13      */
    14     List<User> findAll();
    15 }
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE mapper
     3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     5 <mapper namespace="com.buwei.mapper.UserMapper">
     6     <!--配置查询所有-->
     7     <select id="findAll" resultType="com.buwei.entity.User">
     8         select * from user
     9     </select>
    10 </mapper>

      主要的配置就是Mybatis的配置文件了,需要配置开启一级缓存的配置语句,在文件中有相应的注释,具体配置在第十行:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE configuration
     3         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
     4         "http://mybatis.org/dtd/mybatis-3-config.dtd">
     5 <configuration>
     6 
     7     <settings>
     8         <!--控制台打印日志-->
     9         <setting name="logImpl" value="STDOUT_LOGGING"/>
    10         <!--开启一级缓存-->
    11         <setting name="localCacheScope" value="SESSION"/>
    12     </settings>
    13     <!--配置mybatis的环境-->
    14     <environments default="mysql">
    15         <!--配置mysql的环境-->
    16         <environment id="mysql">
    17             <!--配置事务的类型-->
    18             <transactionManager type="JDBC"></transactionManager>
    19             <!--配置连接数据库的信息,用的是数据源(连接池)-->
    20             <dataSource type="POOLED">
    21                 <property name="driver" value="com.mysql.jdbc.Driver"/>
    22                 <property name="url" value="jdbc:mysql://localhost:3306/mybatiscache"/>
    23                 <property name="username" value="root"/>
    24                 <property name="password" value="root"/>
    25             </dataSource>
    26         </environment>
    27     </environments>
    28 
    29 
    30     <!--告知mybatis映射配置的位置-->
    31     <mappers>
    32         <package name="com.buwei.mapper"></package>
    33     </mappers>
    34 </configuration>

      测试类:MybatisCacheTest,测试创建一个SQLsession的情况下,连续执行五次查询,控制台打印实际的查询:

     1 package com.buwei.test;
     2 
     3 import com.buwei.entity.User;
     4 import com.buwei.mapper.UserMapper;
     5 import org.apache.ibatis.io.Resources;
     6 import org.apache.ibatis.session.SqlSession;
     7 import org.apache.ibatis.session.SqlSessionFactory;
     8 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     9 
    10 import java.io.IOException;
    11 import java.io.InputStream;
    12 import java.util.List;
    13 
    14 /**
    15  * @author buwei
    16  * @date 2018/12/20 12:40
    17  */
    18 
    19 public class MybatisCacheTest {
    20 
    21     public static void main(String[] args) throws IOException {
    22         // 1.读取配置文件
    23         InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
    24         // 2.创建sqlSessionFactory的构建者对象
    25         SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    26         // 3.使用构建者创建工厂对象SQLSessionFactory
    27         SqlSessionFactory factory = builder.build(in);
    28         // 4.使用SQLSessionFactory生产SQLSession
    29         SqlSession session = factory.openSession();
    30         // 5.使用session创建mapper的代理对象
    31         UserMapper userMapper = session.getMapper(UserMapper.class);
    32         // 6使用代理对象执行查询所有方法
    33         for (int i = 0; i < 5; i++) {
    34             List<User> list = userMapper.findAll();
    35             System.out.println(list);
    36         }
    37         // 7.释放资源
    38         session.close();
    39         in.close();
    40     }
    41 }

      执行测试方法,我们会发现在实际的查询过程中,只向数据库执行了一次查询,控制台打印如下:

    Mybatis的二级缓存:

      我们前面讲到的一级缓存,它的共享范围就是在SqlSession中,如果多个SqlSession之间需要共享缓存,这时候就需要使用到二级缓存了。二级缓存的范围是在namespace中的。开启了二级缓存之后,执行查询一级缓存之前,会先查询二级缓存。

      开启二级缓存,我们需要在Mybatis的配置文件中配置:

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

      需要在Mybatis的接口映射文件中配置cache挥着cache-ref,如下:

    1 <cache/>

      创建测试类MybatisCacheTest02:

     1 package com.buwei.test;
     2 
     3 import com.buwei.entity.User;
     4 import com.buwei.mapper.UserMapper;
     5 import org.apache.ibatis.io.Resources;
     6 import org.apache.ibatis.session.SqlSession;
     7 import org.apache.ibatis.session.SqlSessionFactory;
     8 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     9 
    10 import java.io.IOException;
    11 import java.io.InputStream;
    12 import java.util.List;
    13 
    14 /**
    15  * @author buwei
    16  * @date 2018/12/20 12:40
    17  */
    18 
    19 public class MybatisCacheTest02 {
    20 
    21     public static void main(String[] args) throws IOException {
    22         // 1.读取配置文件
    23         InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
    24         // 2.创建sqlSessionFactory的构建者对象
    25         SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    26         // 3.使用构建者创建工厂对象SQLSessionFactory
    27         SqlSessionFactory factory = builder.build(in);
    28         // 4.使用SQLSessionFactory生产SQLSession
    29         SqlSession session01 = factory.openSession();
    30         SqlSession session02 = factory.openSession();
    31         // 5.使用session创建mapper的代理对象
    32         UserMapper userMapper01 = session01.getMapper(UserMapper.class);
    33         UserMapper userMapper02 = session02.getMapper(UserMapper.class);
    34         // 6使用代理对象执行查询所有方法
    35         for (int i = 0; i < 2; i++) {
    36             List<User> list01 = userMapper01.findAll();
    37             System.out.println( "userMapper01读取数据"+ list01);
    38         }
    39         for (int i = 0; i < 2; i++) {
    40             List<User> list02 = userMapper02.findAll();
    41             System.out.println("userMapper02读取数据"+list02);
    42         }
    43         // 7.释放资源
    44         session02.close();
    45         session01.close();
    46         in.close();
    47     }
    48 }

      执行方法之后我们发现在session没有执行commit()方法时,二级缓存并没有起到作用

      我们在userMapper01执行了查询之后执行:

    1 session01.commit();

      然后再次执行测试方法:

      从控制台打印的数据可以知道,session02的查询有使用到缓存。

      还有就是当我们执行了更新数据之后,会清空缓存,这里就没有做展示了,有兴趣的可以自己来测试一下。

      二级缓存的范围是namespace的,然后我们通常就是一张表的查询会对应一个映射文件,就是在我们执行多表查询的时候有时候不同的namespace之间数据更新是感应不到的,这时候就会读取到脏数据,这时候可以使用cache-ref来解决问题,后面有机会会再续写上:)

    如发现有错误欢迎指正,欢迎交流,接受反驳。 -- by不为 :)
  • 相关阅读:
    Borladn传奇终结巨人倒下了
    C#数据导出到excel
    ADO.NET Entity Framework学习笔记(4)ObjectQuery对象
    ADO.NET Entity Framework学习笔记(3)ObjectContext对象[转]
    在Vista,WIN2K8下IE7.0就不能正常访问asp.net development server解决办法
    获取SQL Server表字段的各种属性
    白话说.net事件和委托
    Ado.Net Entity : Object doesn’t display linked members (foreign keys)
    移动飞信WEB发送服务接口
    asp.net FormsAuthentication 认证
  • 原文地址:https://www.cnblogs.com/buwei/p/10148724.html
Copyright © 2020-2023  润新知