精华内容
下载资源
问答
  • 缓存机制
    千次阅读 热门讨论
    2021-12-16 10:12:13

    mybatis提供了缓存机制减轻数据库压力,提高数据库性能。mybatis的缓存分为一级和二级两种:

    • 一级缓存:SqlSession级别的缓存,缓存的数据只在SqlSession内有效
    • 二级缓存:mapper级别的缓存,同一个namespace公用这一个缓存,所以对SqlSession是共享的

    一级缓存:

    一级缓存是基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空。

    一级缓存是SqlSession级别的缓存,在操作数据库的时候需要先创建SqlSession会话对象,在对象中有一个HashMap用于存储缓存数据,此HashMap是当前会话对象私有的,别的SqlSession会话对象无法访问。

    一级缓存是基于SQLSession的缓存,一级缓存的内容不能跨SQLSession。由mybatis自动维护。不同的sqlsession之间的缓存区域是互相不影响的。

    具体流程:

    • 第一次执行select完毕会将查到的数据写入SqlSession内的HashMap中缓存起来
    • 第二次执行select会从缓存中查数据,如果select相同且传参数一样,那么就能从缓存中返回数据,不用去数据库了,从而提高了效率

    注意事项:

    • mybatis默认是开启一级缓存,不需要配置
    • 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中的所有缓存数据,这样可以保证缓存中存的数据永远和数据库中一致,避免出现脏读
    • 一个SqlSession结束后那么它里面的一级缓存也就不存在了。
    • mybatis的缓存是基于[namespace:sql语句:参数]来进行缓存的。意思就是,SqlSession的HashMap存储缓存数据时,是使用[namespace:sql:参数]作为key,查询返回的语句作为value保存的。

    二级缓存:

    二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。作用域为 namespance 是指对该 namespance 对应的配置文件中所有的 select 操作结果都缓存,这样不同线程之间就可以共用二级缓存。

    二级缓存可以设置返回的缓存对象策略:

    • 当 readOnly="true"时,表示二级缓存返回给所有调用者同一个缓存对象实例,调用者可以 update 获取的缓存实例,但是这样可能会造成其他调用者出现数据不一致的情况(因为所有调用者调用的是同一个实例)。
    • 当 readOnly=“false”(默认)时,返回给调用者的是二级缓存总缓存对象的拷贝,即不同调用者获取的是缓存对象不同的实例,这样调用者对各自的缓存对象的修改不会影响到其他的调用者,即是安全的。

    二级缓存是mapper级别的缓存,也就是同一个namespace中的mappe.xml。当多个SqlSession使用同一个Mapper操作数据库的时候,得到的数据会缓存在同一个二级缓存区域。

    二级缓存是基于映射文件的缓存(namespace),缓存范围比一级缓存更大,不同的SQLSession可以访问二级缓存的内容。哪些数据放入二级缓存需要自己指定。

    二级缓存默认是没有开启的。需要在setting全局参数中配置开启二级缓存

    <settings>
        <setting name="cacheEnabled" value="true"/>    <!--默认是false:关闭二级缓存-->
    <settings>
    

    在mapper.xml中配置:

    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
    

    这里配置了一个LRU缓存,并每隔60秒刷新,最大存储512个对象,而却返回的对象是只读的。

    • eviction:代表的是缓存回收策略,目前MyBatis提供以下策略:
      • LRU(Least Recently Used):最近最少使用的,最长时间不用的对象
      • FIFO(First In First Out):先进先出,按对象进入缓存的顺序来移除他们
      • SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
      • WEAK:弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,
        移除最长时间不用的对形象
    • flushInterval:刷新间隔时间,单位为毫秒,这里配置的是60000秒刷新,如果你不配置它,那么当
      SQL被执行的时候才会去刷新缓存。
    • size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。
    • readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有办法修改缓存,他的默认值是false,不允许我们修改。

    对于访问多的查询请求并且用户对查询结果实时性要求不高的情况下,可采用mybatis二级缓存,降低数据库访问量,提高访问速度。
    若想禁用当前select语句的二级缓存,添加useCache=“false”(默认情况下为true)就可以了:

    <select id="getUserById" parameterType="int" resultType="user" useCache="false">
    

    在实际开发中,针对每次查询都需要最新数据的sql,要设置为useCache=“false” ,禁用二级缓存

    具体流程:

    • 当一个sqlseesion执行了一次select后,关闭此session的时候,会将查询结果缓存到二级缓存
    • 当另一个sqlsession执行select时,首先会在他自己的一级缓存中找,如果没找到,就回去二级缓存中找,找到了就返回,就不用去数据库了,从而减少了数据库压力提高了性能

    注意事项:

    • 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前mapper缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
    • mybatis的缓存是基于[namespace:sql语句:参数]来进行缓存的,意思就是,SqlSession的HashMap存储缓存数据时,是使用[namespace:sql:参数]作为key,查询返回的语句作为value保存的。

    二级缓存的局限性
    mybatis二级缓存对细粒度级别的数据的缓存实现不好,比如:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息。因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。
    解决此类问题需要在业务层根据需求对数据有针对性缓存。

    SpringBoot整合Mybatis可通过以下设置二级缓存:

    • #使全局的映射器启用或禁用缓存。
      mybatis.configuration.cache-enabled=true
    • #全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。
      mybatis.configuration.lazy-loading-enabled=true
    • #当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。
      mybatis.configuration.aggressive-lazy-loading=true
    • #是否允许单条sql 返回多个数据集 (取决于驱动的兼容性) default:true
      mybatis.configuration.multiple-result-sets-enabled=true
    • #是否可以使用列的别名 (取决于驱动的兼容性) default:true
      mybatis.configuration.use-column-label=true
    • #允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。 default:false
      mybatis.configuration.use-generated-keys=true
    • #指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射\u3000PARTIAL:部分 FULL:全部
      mybatis.configuration.auto-mapping-behavior=partial
    • #这是默认的执行类型 (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新)
      mybatis.configuration.default-executor-type=simple
    • #使用驼峰命名法转换字段。
      mybatis.configuration.map-underscore-to-camel-case=true
    • #设置本地缓存范围 session:就会有数据的共享 statement:语句范围 (这样就不会有数据的共享 ) defalut:session
      mybatis.configuration.local-cache-scope=session
    • #设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER,插入空值时不需要指定类型
      mybatis.configuration.jdbc-type-for-null=null
    • #如果数据为空的字段,则该字段省略不显示,可以通过添加配置文件,规定查询数据为空是则返回null。
      mybatis.configuration.call-setters-on-nulls=true

    比如,通过以下代码可以禁用MyBatis的二级缓存:

    mybatis:
      type-aliases-package: com.hc.domain
      configuration:
        map-underscore-to-camel-case: true
        cache-enabled: false #禁用二级缓存
      mapper-locations: mappers/*.xml  
    
    更多相关内容
  • 主要介绍了全面了解django的缓存机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Mysql执行过程与BufferPool缓存机制.png
  • 摘要:本文作者,腾讯游戏平台与社区产品部安卓开发组高级工程师贺辉超详细分析了各种缓存机制的原理、用法及特点,并针对Android移动端Web性能加载优化的需求,帮助开发者选择如何利用适当缓存机制来提高Web的加载...
  • 浅谈Ajax的缓存机制

    2021-01-19 19:12:33
    Ajax的缓存机制和浏览器处理资源时的缓存机制是一样的。 三条简单规则: 只要是URL相同的GET请求,浏览器会使用缓存(当然还要看服务器的Cache-Control/Expires/Last-Modified/ETag头的设置)。 只要是POST请求,...
  • 主要介绍了Python代码块及缓存机制原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • HTTP缓存机制

    千次阅读 2021-08-21 20:23:38
    由请求行、请求头部和...头部携带了一些信息,可以实现一些功能,比如缓存。 请求数据:也就是真正要传输的数据。 2. HTTP响应报文: 类似的,由状态行、响应头部、响应数据3个部分构成。 状态行:指定Http协议版本

    1. HTTP请求报文:

    请求行请求头部请求数据3个部分组成,如下图所示:

    在这里插入图片描述
    请求行:从上图中可以看见有请求方法(GETPOSTDELETEPUTHEADTRACEOPTIONS),请求URL地址,Http所使用的协议版本,然后是回车换行;

    请求头部:以键值对的方式存储,每一条头部都以回车换行结尾。头部携带了一些信息,可以实现一些功能,比如缓存。

    请求数据:也就是真正要传输的数据。

    2. HTTP响应报文:

    类似的,由状态行响应头部响应数据3个部分构成。

    在这里插入图片描述

    状态行:指定Http协议版本,状态码,状态描述信息,然后回车换行;

    响应头部:和请求报文类似,这里不介绍;

    响应正文:也就是响应成功后返回的结果;

    3. 状态码

    状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:

    • 1xx:指示信息–表示请求已接收,继续处理
    • 2xx:成功–表示请求已被成功接收、理解、接受
    • 3xx:重定向–要完成请求必须进行更进一步的操作
    • 4xx:客户端错误–请求有语法错误或请求无法实现
    • 5xx:服务器端错误–服务器未能实现合法的请求

    常见状态代码、状态描述、说明:
    200 OK //客户端请求成功
    206 Partial Content // 成功执行了一个部分请求,用于断点续传
    301 Moved Permanent // 请求的URL被移除, 用于重定向
    304 Not Modified // 条件请求再验证,资源未改变,用于HTTP缓存
    400 Bad Request //客户端请求有语法错误,不能被服务器所理解
    401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
    403 Forbidden //服务器收到请求,但是拒绝提供服务
    404 Not Found //请求资源不存在,eg:输入了错误的URL
    500 Internal Server Error //服务器发生不可预期的错误(服务器内部错误)
    503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

    4. 报文头部

    开发者会经常使用到Http报文的头部信息,所有有必要了解一些头部信息:

    Expires:表示过期时间,在这个日期之后就认为过期。(HTTP1.0标准;当Cache-Control和该字段同时存在的条件下,Cache-Control的优先级更高);
    Cache-Control:控制缓存行为,标明缓存的最大存活时常;可取值通常为如下几个:

    • private:客户端可以缓存;
    • public:客户端和服务器都可以缓存;
    • max-age=xx:缓存内容将在xx秒后失效;
    • no-cache:需要使用协商缓存来验证缓存数据;
    • no-store:所有内容将都不会缓存,强缓存和协商缓存都不会触发;
    • must-revalidate:缓存必须在使用前验证旧资源的状态,不可使用过期资源;

    Last-Modified:服务器告诉客户端,资源的最后修改时间;
    E-tag:当前资源在服务器的唯一标识(字符串),可用于判断资源的内容是否被修改了。
    Date:创建报文的日期和时间,服务器告诉客户端,该资源的发送时间;
    Accept:客户端可以识别的内容类型列表,或者媒体类型;
    Host:请求资源所在的计算机主机名和端口号;
    Transfer-Encoding:指定报文主题的传输编码方式;
    Via:追踪客户端和服务器之间之前的请求和响应的传输路径;
    Warning:错误通知;
    If-Match:告知服务器匹配资源所用的实体标记值;
    If-Modified-Since:比较资源的更新时间,告知服务器该时间之后已更新资源,则获取;
    If-Range:资源未更新时发送实体Byte的范围请求;
    If-Unmodified-Since:比较资源的更新时间,告知服务器该时间之后未更新资源,则获取;
    User-AgentHTTP客户端信息;
    Age:返回资源创建到这次请求所经历的时间;

    5. HTTP的缓存机制

    HTTP的缓存机制简单来说可以描述为这么一个过程:

        当客户端向服务器发起一条请求,服务器会返回该请求的对应资源到客户端,此时客户端可以对这个信息进行处理,在本地存储一个副本,当下次在进行同一个请求的时候,就可以直接从本地的缓存中直接返回结果给客户端显示,这个过程也就是HTTP的缓存机制。

    HTTP缓存可以简单的划分成两种类型:强缓存200)与协商缓存304

    • 强缓存(200):如果请求的资源来本地缓存中还没有过期,就直接使用本地的副本,无需请求。强缓存的过期时间由ExpiresCache-Control来控制。
    • 协商缓存(304):请求从客户端发起,请求前先从本地缓存中取出该缓存的一个标识,然后向服务器发送验证请求,如果服务器没有更新资源,则让客户端使用本地缓存即可。否则返回新的资源。使用Last-ModifiedE-tag

    5.1 强缓存

    1. 缓存命中情况:在这里插入图片描述
    2. 缓存未命中情况:在这里插入图片描述

    5.2 协商缓存

    1. 缓存命中情况:在这里插入图片描述
      这里协商缓存缓存命中情况,是和服务器协商。这里服务器通知客户端资源没有更新,也就是说可以使用之前你缓存的数据,服务器会返回状态码304,标识资源未变。

    2. 缓存未命中情况:在这里插入图片描述

    协商缓存未命中,标识和服务器协商失败,服务器会返回一个新的资源和对应的字符串标识。新资源有新的最后一次修改时间和服务器中的唯一标识

    5.3 HTTP的缓存机制

    这两个缓存的统一,通常也就是HTTP缓存机制:
    在这里插入图片描述
    大致流程如下:

    • 服务器收到请求时,会在200 OK中回送该资源的Last-ModifiedETag头。客户端收到信息后,判断响应报文头部的Cache-Controll是否是no-store,如果不是则支持浏览器缓存,就新建缓存。否则,禁止缓存。
    • 客户端将该资源保存在cache中,并记录该资源的Last-ModifiedETag的值。
    • 当客户端需要发送相同的请求时,根据Date + Cache-control来判断是否缓存过期
    • 如果过期了,先判断缓存中对应的资源是否有响应头Etag,有就会在请求中携带If-None-Match;然后判断该资源的缓存中是否有Last-Modified的响应头,如果有会再请求中携带If-Modified-Since。需要注意的是,只有两个都有才会向服务器请求文件是否变动的请求,否则就直接请求资源。
    • 两个头的值分别是响应中Last-ModifiedETag头的值。
    • 服务器通过这两个头判断本地资源未发生变化,客户端不需要重新下载,返回304响应。
    • 否则服务器返回新的数据和缓存规则,客户端再重新存储缓存。

    注意:当指定cache-control:no-store,缓存都无效。

    6. 缓存案例

    6.1 SpringBoot静态资源缓存

    因为HTTP缓存的强大性,在开发中主要用于静态资源,比如CSSJavaScript和图像等。在SpringBoot中可以通过对静态资源的访问路径的配置处,添加缓存控制就可以实现对静态资源的HTTP缓存,比如:

    @Configuration
    public class MyWebMvcConfigurer implements WebMvcConfigurer {
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/**")
                    .addResourceLocations("classpath:/static/")
                    .setCacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES));;
        }
    }
    

    比如在我项目的静态资源目录中,我添加了一个图片:
    在这里插入图片描述
    然后来尝试访问,在访问过继续访问的时候,如下:
    在这里插入图片描述
    状态码为304,也就是告诉客户端请求资源未改变。可以使用缓存。

    6.2 非静态资源缓存

    类似的,这里我使用UserMap来模拟数据库,存储用户数据,建立Controller如下:

    @RestController
    public class RetrofitController {
    
        @GetMapping(value="/test/1.0/users")
        public ResponseEntity<Set<User>> getUsers(){
            CacheControl cacheControl = CacheControl.maxAge(30, TimeUnit.MINUTES);
            return ResponseEntity.ok()
                    .cacheControl(cacheControl)
                    .header(HttpHeaders.LAST_MODIFIED, getTime())
                    .body(UserMap.getDataBaseUsers());
        }
    
        private String getTime(){
            ZonedDateTime zonedDateTime = ZonedDateTime.now().with(LocalTime.MAX);
            return zonedDateTime.format(DateTimeFormatter.RFC_1123_DATE_TIME);
        }
    }
    

    请求测试:
    在这里插入图片描述

    注意到为了设置缓存控制的HTTP首部,这里使用了ResponseEntity来包装返回的数据。

    测试效果:
    在这里插入图片描述
    需要注意的是,如果头部信息同时存在Cache-ControlExpires这两个缓存标识,那么客户端仅使用Cache-Controll。且我们需要为资源设置一个最后一次修改的时间,即Last-Modify。这里我直接设置为了一个未来的时间,也就是保证在当前访问的时候,这个标识这个资源没有被更新。

    展开全文
  • 针对.net框架下,建立配置文件全局共享机制解决方法,利用application实现高速缓存全局共享,并与session进行区分
  • Mybatis的缓存机制

    千次阅读 2022-03-24 10:53:08
    Mybatis的缓存机制mybatis的代理详解mybatis的缓存机制缓存介绍一级缓存一级缓存介绍一级缓存测试二级缓存二级缓存原理二级缓存使用步骤二级缓存使用测试 mybatis的代理详解 Java中动态代理主要是JDK动态代理(接口...

    mybatis的代理详解

    Java中动态代理主要是JDK动态代理(接口),CGLib动态代理(类继承)

          SqlSession sqlSession = sqlSessionFactory.openSession();
    
    
            /**
             *在通过sqlSession.getMapper可以获取一个代理对象
             * 对于StudentMapper并没有显性的实现该接口的实现类,
             * 该对象是在运行时动态产生的,该对象就是动态代理对象
             *
             * JDK动态代理
             * 1、首先存在接口(StudentMapper.java)
             * 2、必须存在该接口的实现类(sqlSession.selectOne)
             * 3、实现invocationHandler辅助类
             * 4、通过Proxy类来产生代理对象
             */
    
            //单个对象原始调用方式
    //        Student student = sqlSession.selectOne("com.tulun.Mybatis.mapper.StudentMapper.selectStudentById", 4);
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            Student student = studentMapper.selectStudentById(4);
            System.out.println(student);
    

    mybatis是否用到了JDK动态代理相关的接口和类?产生代理对象如何组织?

    mybatis中代理对象的获取是通过如下方法:

     sqlSession.getMapper(StudentMapper.class);
    

    mapper接口是如何添加进去的?
    通过Java代码形式来进行数据源、映射文件的配置形式如下:

            Configuration configuration = new Configuration();
            PooledDataSourceFactory dataSourceFactory = new PooledDataSourceFactory();
            DataSource dataSource = dataSourceFactory.getDataSource();
            JdbcTransactionFactory jdbcTransactionFactory = new JdbcTransactionFactory();
            //设置环境
            Environment environment = new Environment("test", jdbcTransactionFactory, dataSource);
            configuration.setEnvironment(environment);
    
            //设置mapper接口
            configuration.addMapper(StudentMapper.class);
            new SqlSessionFactoryBuilder().build(configuration);
    

    重点在于接口的添加形式:

    configuration.addMapper(StudentMapper.class);
    

    在Configuration类中:

      public <T> void addMapper(Class<T> type) {
        mapperRegistry.addMapper(type);
      }
    

    mapper在Configuration类中没有做任何事,只是添加到mapperRegistry类中。

    public <T> void addMapper(Class<T> type) {
        if (type.isInterface()) {//只允许添加接口
          if (hasMapper(type)) {//不允许重复添加
            throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
          }
          boolean loadCompleted = false;
          try {
            knownMappers.put(type, new MapperProxyFactory<T>(type));
            MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
            parser.parse();
            loadCompleted = true;
          } finally {
            if (!loadCompleted) {
              knownMappers.remove(type);
            }
          }
        }
    

    执行的configuration.addMapper(StudentMapper.class),实际上最终被放入HashMap中,其命名knownMappers,它是mapperRegistry类中的私有属性,是一个HashMap对象,key是接口class对象,value是MapperProxyFactory的对象实例

    通过getMapper获取代理对象。
    DefaultSqlSession类:

      public <T> T getMapper(Class<T> type) {
        return configuration.<T>getMapper(type, this);
      }
    

    configuration类中存放所有的mybatis全局配置信息,从参数上可以知道class类型。
    configuration类:

      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return mapperRegistry.getMapper(type, sqlSession);
      }
    

    configuration类中getmapper调用了mapperRegistry.getMapper,mapperRegistry中存放一个HashMap

    mapperRegistry类:

     private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
    
    
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        if (mapperProxyFactory == null) {
          throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        }
        try {
          return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception e) {
          throw new BindingException("Error getting mapper instance. Cause: " + e, e);
        }
      }
    

    调用mapperRegistry类中的getMapper方法,该方法中会到hashmap中通过类名获取对应的value值,是MapperProxyFactory对象,然后调用newInstance方法,该方法是创建了一个对象。

    public class MapperProxyFactory<T> {//映射器代理工厂
    
      private final Class<T> mapperInterface;
      private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
    
      @SuppressWarnings("unchecked")
      protected T newInstance(MapperProxy<T> mapperProxy) {
          //使用的是JDK自带的动态代理对象生成代理类对象
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
      }
    
      public T newInstance(SqlSession sqlSession) {
        final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
      }
    
    }
    
    public class MapperProxy<T> implements InvocationHandler, Serializable {
    //实现了InvocationHandler接口
    
      @Override
        //代理之后,所有的mapper的方法调用,都会调用这个invoke方法
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
          try {
            return method.invoke(this, args); //该位置就调用了原始的调用方法:SQLSession.selectOne
          } catch (Throwable t) {
            throw ExceptionUtil.unwrapThrowable(t);
          }
        }
        final MapperMethod mapperMethod = cachedMapperMethod(method);
        //执行CURD操作  
        return mapperMethod.execute(sqlSession, args);
      }
    
    
    }
    

    mybatis中getmapper的代理对象的获取,使用的是JDK动态代理,在MapperRegistry类中的HashMap中存放了所有的mapper接口,key是接口的类名信息,value是MapperProxyFactory类型实例,getmapper操作会是当前对象调用newInstance操作,该操作会调用Proxy.newProxyInstance核心在于调用InvocationHandler接口,实现了invoke方法,除了调用原始的接口调用,而且还对调用进行增强,进行了方法缓存,且最终会执行增删改查操作。

    总结Mapper接口方法执行的几个点:

    1. Mapper接口初始在SQLSessionFactory注册的。
    2. Mapper接口注册在MapperRegistry类的HashMap中,key是mapper的接口类名,value是创建当前代理工厂。
    3. Mapper注册之后,可以从过SQLSession来获取get对象。
    4. SQLSession.getMapper运用了JDK动态代理,产生了目标Mapper接口的代理对象,动态代理的代理类是MapperProxy,实现了增删改查调用。

    mybatis的缓存机制

    缓存介绍

    mybatis中提供查询缓存,用于减轻数据库的压力,提高数据库的性能。
    mybatis提了了一级缓存和二级缓存:
    在这里插入图片描述
    一级缓存是SQLSession级别缓存,在操作数据库时都需要构造SQLSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据,不同的SQLSession之间的缓存数据区域是互不影响的。
    一级缓存的作用于是在同一个SQLSession,在同一个SQLSession中执行相同的两次SQL,第一次执行完毕在后会将数据写到缓存中,第二次从缓存中进行后去就不在数据库中查询,从而提高了效率,
    当一个SQLSession结束后该SQLSession中的一级缓存也就不存在了,mybatis默认开启一级缓存。

    二级缓存是mapper级别缓存,多个SQLSession去操作同一个mapper的SQL语句,多个SQLSession操作都会存在二级缓存中,多个SQLSession共用二级缓存,二级缓存是跨SQLSession的。
    二级缓存是多个SQLSession共享的,作用域是mapper下的同一个namespace。不同的SQLSession两次执行相同的namespace下的SQL最终能获取相同的SQL语句结果。
    mybatis默认是没有开启二级缓存的,需要在全局配置文件中配置开启二级缓存。

    一级缓存

    一级缓存介绍

    在这里插入图片描述
    每个SqlSession中持有一个执行器Executor,每个执行器中有一个Local Cache,当用户发起查询时,mybatis根据当前执行的语句生成mapperStatement,在Local Cache中进行查询,如果缓存命中的话,直接返回给用户,如果没有命中,查询数据库,结果写入Local Cache中,最后返回给用户。

    通过ID查询用户信息:
    在这里插入图片描述
    缓存生效失效时机:
    如果是连续的查询同一个数据操作,在第一次查询之后,后续查询都可以命中缓存。
    如果在查询之后,紧接着是进行变更操作,就会导致缓存失效。

    一级缓存测试

    mybatis是默认支持一级缓存,不需要做其他配置。

    测试1:同一个SQLSession下连续进行查询操作:

            //同一个SQLSession连续进行查询操作
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            //第一次查询操作
            System.out.println("第一次查询开始......");
            Student student = studentMapper.selectStudentById(4);
            System.out.println("第一次查询结束......");
    
            System.out.println("第二次查询开始......");
            Student student1 = studentMapper.selectStudentById(4);
            System.out.println("第二次查询结束......");
    
    
    

    通过执行结果可知:第一次查询会查询数据库,第二次查询操作是没有查询SQL,即通过缓存查询到结果返回。

    测试2:第一次查询结束后,对数据进行变更操作,再次执行查询操作:

            //同一个SQLSession连续进行查询操作
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            //第一次查询操作
            System.out.println("第一次查询开始......");
            Student student = studentMapper.selectStudentById(4);
            System.out.println("第一次查询结束......");
    
            //对数据进行变更操作
            System.out.println("变更操作开始....");
            studentMapper.updateNameById(4,"test");
            sqlSession.commit();
            System.out.println("变更操作结束....");
    
            //第二次查询
            System.out.println("第二次查询开始......");
            Student student1 = studentMapper.selectStudentById(4);
            System.out.println("第二次查询结束......");
    
    

    在查询结束后,如果对于数据进行变更操作,会删除掉缓存,导致第二次查询依然需要进入到数据库。

    case3:不同的SQLSession下同一个操作是否会命中缓存:

    SqlSession sqlSession = sqlSessionFactory.openSession();
            //分别数据不同的SQLSession是否会命中缓存
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            //第一次查询操作
            System.out.println("第一次查询开始......");
            Student student = studentMapper.selectStudentById(4);
            System.out.println("第一次查询结束......");
    
            SqlSession sqlSession1 = sqlSessionFactory.openSession();
            StudentMapper studentMapper1 = sqlSession1.getMapper(StudentMapper.class);
            //第二次查询
            System.out.println("第二次查询开始......");
            Student student1 = studentMapper1.selectStudentById(4);
            System.out.println("第二次查询结束......");
    

    不同的SQLSession的一级缓存是无法共享的。

    二级缓存

    mybatis中二级缓存是mapper级别的缓存,默认是关闭的。
    对于一个mapper下的不同的SQLSession可以共享二级缓存。
    不同的mapper是相互隔离的。
    二级缓存的特点是需要打开二级缓存的配置,并且需要映射的java类需要实现序列化。

    二级缓存原理

    在这里插入图片描述
    二级缓存和一级缓存的区别:
    二级缓存范围更大,多个SQLSession可以共享一个mapper级别的二级缓存,数据类型依然是HashMap来存储二级缓存内容,mapper是按照namespace划分,如果namespace相同则使用同一个二级缓存,
    一级缓存范围会更小,是一个SQLSession级别。

    二级缓存使用步骤

    第一步:在mybatis的全局配置文件中开启二级缓存:

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

    第二步:将映射的pojo类实现序列化:

    public class Student implements Serializable
    

    第三步:在mapper配置文件中使用cache标签:

    <!--
        cache和二级缓存相关标签
        eviction属性:代表缓存的回收策略,mybatis提供了回收策略如下:
        LRU:最近最少使用,对于最长时间不用的对象进行回收
        FIFO:先进先出,按照帝乡进入缓存的顺序来进行回收
        SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
        WEAK:弱引用,基于垃圾回收器状态和弱引用规则的对象
    
        flushInterval属性:刷新间隔时间,单位是毫秒
        size属性:引用数目,代表缓存可以存储最多多少个对象
        readOnly属性:只读,意味着缓存数据只能读取不能修改
        -->
        <cache eviction="FIFO" flushInterval="1000" size="1024" readOnly="false"/>
    
    

    注:在select查询导致上使用属性:
    useCache=“true” 缓存的使用和禁止
    flushCache=“true” 刷新缓存

    二级缓存使用测试

        //二级缓存的测试
        @Test
        public void testCache2() {
            //不同的SQLSession会话进行相同的SQL查询操作
            //SQLSession1实例
            SqlSession sqlSession = sessionFactory.openSession();
            Student23Mapper student23Mapper = sqlSession.getMapper(Student23Mapper.class);
            //SQLSession2实例
            SqlSession sqlSession1 = sessionFactory.openSession();
            Student23Mapper student23Mapper1 = sqlSession1.getMapper(Student23Mapper.class);
            //sqlsession实例3
            SqlSession sqlSession2 = sessionFactory.openSession();
            Student23Mapper student23Mapper2 = sqlSession2.getMapper(Student23Mapper.class);
    
    
            //第一次查询id为1的用户
            Student23 student23 = student23Mapper.selectStudentByUid(1L);
            System.out.println(student23);
            //这里执行关闭操作,将SQLSession中的数据写入到二级缓存区域
            sqlSession.close();
    
    
    
            //第二次查询id为1的用户
            Student23 student24 = student23Mapper1.selectStudentByUid(1L);
            System.out.println(student24);
            sqlSession1.close();
        }
    

    在这里插入图片描述

    表明不同的SQLSession可以共享一个二级缓存。

    底层:二级缓存是一个Cache接口的实现类,一级缓存是一个localCache是一个HashMap的属性,
    执行过程先经过二级缓存,在二级缓存未命中时才会走一级缓存。

    展开全文
  • 浏览器缓存机制详解

    千次阅读 2022-01-25 10:12:25
    一、为什么需要缓存 在前端开发中,我们主要追求的是性能和用户体验。对于一个网站查看性能最简单的 方式就是打开网站的速度。而一个好的缓存策略可以大大提升网站的性能。使得已经 下载后的资源被重复利用。减少...

    一、为什么需要缓存

    在前端开发中,我们主要追求的是性能和用户体验。对于一个网站查看性能最简单的
    方式就是打开网站的速度。而一个好的缓存策略可以大大提升网站的性能。使得已经
    下载后的资源被重复利用。减少客户端和服务器之间的请求次数,减少带宽,减少网
    络负荷。
    

    二、什么是缓存

    对于web缓存,主要是针对一些web资源(html, js,图片,数据等),就是介于web
    服务器和浏览器之间的文件数据副本。当我们第一次打开某一个网页时,浏览器向服
    务器发起请求,请求所需要的资源。如果我们使用了web缓存,当我们下一次再次
    访问该网站页面的时候,我们可以根据一些缓存策略,来决定是否直接使用缓存中的
    一些资源,还是再次向服务端发起请求,从而避免再次向服务器发起请求,减少客户
    端和服务器之间通信的时延。
    

    三、缓存的作用

    1、减少网络带宽的消耗
    2、降低服务器压力
    3、减少网络延时,加快页面打开速度。
    

    四、浏览器的缓存机制

    对于浏览器端的缓存来说,规则是在http协议头和html的mate标签中定义的,他们
    分别从过期机制和校验值来判断是否直接使用该缓存,还是需要从服务器去获取更新
    的版本。
    1、新鲜度(过期机制):也就是缓存副本的有效期。一个缓存副本必须满足以下条件
    之一,浏览器才会认为它是有效的,足够新的,才会直接使用缓存。
    (*)http协议头中存在过期时间等信息,并且仍在有效期内。
    (*)浏览器已经使用过这个缓存副本,并且在一个会话中已经检查过新鲜度。
    2、校验值(验证机制):服务器相应中,在响应头中存在Etag标签,用来验证资源是
    否更改的标识,如果缓存的标识和服务器的标识相同则无需重新请求资源,如果不相
    同,则重新发送资源请求。
    

    五、浏览器缓存控制
    1、html中的mate标签设置缓存

    例如
    设置过期时间
    <meta http-equiv="expires" content="Wed, 20 Jun 2007 22:33:00 GMT"> 
    设置缓存
    <meta http-equiv="Pragma" content="no-cache"

    2、与缓存有关的字段

    Cache-control:max-age(单位为s),当某一个资源的响应头设置max-age=3600,
    则表示在1h时间内,服务器的资源发生变化,浏览器都不会想服务器发送该资源的请
    求,直接使用缓存。并且max-age会覆盖Expires。
    如下图所示
    

    在这里插入图片描述

    Cache-control:s-maxage,s-maxage表示CDN缓存,也就是代理缓存,如果设置s-maxage=60,表示60秒内无论cdn服务器的该资源发生怎么样的改变,都不会重新请求,并且s-maxage会覆盖max-age和Expires.
    
    Cache-control:public,指定是否是共享缓存,如果设置Cache-control的值设置为public,则表示多个浏览器之间可以共同使用该资源缓存。
    如果没有指定Cache-control是为private还是public,则默认是public.
    

    在这里插入图片描述

    Cache-control:private,表示该缓存是私有的,不存在用户共享。
    

    在这里插入图片描述

    Cache-control:no-cache;Cache-control的值设置为no-cache并不代表不缓
    存,浏览器是缓存的,但是当每一次访问该资源的时候,都要向服务器请求查看资源
    是否改变,如果改变,则直接重新下载,如果没有改变,则使用缓存。可以在设置完no-cache之后,在设置private,以及设置过期时间为过去的时间。
    
    Cache-control:no-store,表示严格不缓存,每一次资源必须从服务器上重新获取。
    
    Expires:缓存过期时间,Expires=max-age + 最后一次请求的时间。Cache-control和Expires相比,Cache-control的优先级更高。Expires需要和Last-modifyed来一起使用。
    

    在这里插入图片描述

    Last-Modified和if-modified-since:last-modified是响应头上的属性,if-modifyed-since
    是请求头的数据。该属性值需要cache-control配合使用。当再次向服务器发送请求
    该资源时,会携带if-modified-since的请求头字段,到服务器比对和last-
    modified是否相同。如果相同则直接返回304,直接使用缓存,如果不相同,则再次
    请求新的数据,返回200.
    
    ETag和if-None-Match:这俩个属性其实和last-modified和if-modified-since
    类似。不过Etag是服务器更加内容产生的hash字符串,并且Etag是响应头内容。
    if-None-match是请求头的内容。当再次向服务器发送请求某一个资源时,请求头会
    携带if-None-match属性,到达服务器后,和Etag进行比对。如果相同,则返回
    304,如果不相同则返回该资源,并且状态码为200.
    

    六、缓存报文头种类和优先级

    Cache-control和Expires比较
    Cache-control的优先级比Expires的优先级高。
    
    Last-Modified和ETag比较
    Etag的优先级要高于Last-modified,当在请求头中会先进行ETag比较,然后再进行Last-modified比较,如果两者都相等,则直接返回304,直接使用缓存资源。
    两者比较一下,你可能会觉得两者的功能差不多,但是为什么要在http1.1中新增Etag呢?
    1、Last-modified精确到秒,如果在一秒钟内修改多次文件,则无法准确拿到最新的文件。
    2、如果缓存文件,打开后但是不修改内容,导致Last-modified发生变化,下一次就没有办法使用缓存文件了。
    3、可能存在服务器没有获取准确的修改时间,或者代理服务器时间不一致的情况。
    
    Last-Modified/Etag和Cache-control/Expires比较
    Cache-control/Expries的优先级要比Last-Modified/Etag的优先级高,当第二次发送请求时,会首先查看Cache-control/Expries是否过期,如果没有过期,则任然使用该资源,如果过期了,则再次向服务器发送请求来请求最新的资源。到达服务器时通过比对Last-modified/Etag是否和原来的值相等,来判断资源是否改变,如果没有改变,则返回304。如果改变了,则返回最新的资源,并且状态码为200.
    

    七、有哪些请求不能进行缓存的

    无法被浏览器缓存的请求
    1、http信息头部cache-control:no-cache , pragma: nocache或者使用cache-control:max-age=0
    2、根据cookie,认证信息决定输入内容的信息是否可以被缓存的。
    3、经过https加密的请求。
    4、post请求无法被缓存。
    5、在http响应头中不存在last-modified/Etag和cache-control/expires等。
    

    八、使用缓存流程
    在这里插入图片描述

    上面的过程可以分为三个阶段:
    1、本地缓存阶段:如果本地存在缓存,并且通过检查本地资资源的缓存并没有过
    期,则直接使用本地缓存。
    2、协商缓存阶段:如果在本地存在该资源,但是本地资源已经过期,此时就需要封
    装http请求,向服务端发送请求,检查是否存在更改资源。如果资源没有更改,则直
    接返回304,直接在本地使用资源。
    3、缓存失败阶段:如果资源发生了更改,则重新返回最新的资源,并且返回状态码为
    200。如果此时不存在该资源,则直接返回404。
    

    九、用户行为与缓存的关系

    用户在浏览器采用一些操作,例如,返回上一阶段,下一阶段,刷新页面,强制刷新
    等操作,这些对于一些缓存属性的影响是不一样的。下面将进行详细解读。
    1、刷新(仅仅是F5刷新):此时对于cache-control/Expires是不生效的,但是last-modified/Etag都生效的,所以此时会向服务器发起请求,用来判断目标文件是否发生变化。
    2、强制刷新(F5刷新+ctrl):此时对于cache-control/expires和last-modified/Etag都不生效,此时必须从服务器拿到新数据。
    3、回车或者转向:此时所有的缓存都生效。
    

    十、从缓存角度改善站点

    1、同一个资源保证只有一个稳定的url地址。
    2、css,js,图片资源增加http缓存头,入口html文件不被缓存。
    3、减少对cookie的依赖
    4、减少对http协议加密的使用。
    
    展开全文
  • MySQL缓存机制

    2021-09-28 09:51:09
    MySQL缓存机制即缓存sql 文本及缓存结果,用KV形式保存再服务器内存中,如果运行相同的sql,服务器直接从缓存中去获取结果,不需要再去解析、优化、执行sql MySQL缓存失效 在表的结构或数据发生改变时,查询缓存中...
  • 浏览器缓存机制

    2016-12-06 11:58:03
    浏览器缓存机制、Expires策略(http1.0)和Cache-control策略(http1.1)、Last-Modified/If-Modified-Since、ETag/If-None-Match
  • 【浏览器】浏览器的缓存机制

    千次阅读 2022-03-11 20:30:32
    浏览器缓存机制
  • HTTP缓存机制详解

    千次阅读 2022-02-21 10:54:01
    HTTP缓存机制详解
  • MyBatis的缓存机制详解

    2022-06-03 10:24:21
    MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制,缓存可以极大的提升查询效率。MyBatis中默认定义了两级缓存,分别是一级缓存和二级缓存。 (1) 默认情况下,只有一级缓存(SqlSession级别的...
  • 缓存机制简单总结可以说是空间换时间,被用于提升系统交互的效率。而有趣的是,这种缓存机制令人惊奇并且优美的遵循着“几何分形”的规律,也就是几何分形学中的“自相似性”。徐汉彬曾在阿里巴巴和腾讯从事4年多的...
  • 缓存可以说是网站性能优化非常有用的一种方式。一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。 对于一个数据请求来说,可以分为发起网络...
  • 针对CCN现有缓存机制中存在的"无序缓存"的问题,文中提出了选择性缓存机制SC(Selective Caching).它根据用户的潜在需求和内容的流行规律,只在必要的节点上选择性地(而不是沿着内容传输路径处处地)缓存.同时,采用带宽...
  • 浏览器的缓存机制

    千次阅读 2022-01-28 02:21:15
    什么是浏览器的缓存机制 浏览器的缓存机制就是把一个请求过的web资源(例如:html页面、图片、js、数据等)拷贝一份副本储存在浏览器中;缓存会根据进来的请求保存输出内容的副本,当下一个请求到来的时候,如果是...
  • 针对信息中心网络(ICN)内置缓存系统中的海量内容块流行度获取和存储资源高效利用问题,以最大化节省内容访问总代价为目标,建立针对内容块流行度的缓存收益优化模型,提出了一种基于收益感知的缓存机制。...
  • Integer的缓存机制

    千次阅读 2022-03-30 21:19:50
    文章目录一 现象二 Integer的缓存机制2.1 自动装箱等效于valueOf2.2 valueOf2.3 IntegerCache三 为什么要有缓存机制3.1 原因3.2 其他包装对象的缓存 一 现象 在引入Integer的缓存机制前,可以先判断一下以下几种情况...
  • 浏览器缓存机制详细知识点梳理 在前端的性能优化中,浏览器缓存是很重要的一环。比如在页面前进或者后退,发现丝毫不卡顿很流畅,就是缓存机制的力量。 一、什么是缓存 浏览器缓存Brower Caching是浏览器对之前请求...
  • Redis缓存机制

    千次阅读 2021-08-10 11:59:33
    redis缓存机制 一、缓存更新 缓存更新的策略有很多,这里介绍两种比较主要的情况: 第一种情况,先更新数据库再同步更新缓存或者先更新缓存再同步更新数据库,其实都属于write through,同步更新的好处在于可以很好...
  • Android WebVIew缓存机制详解

    千次阅读 2020-02-25 15:39:18
    Android WebView除了新的File System缓存机制(H5页面新加入的缓存机制,后面会进行简单介绍)还不支持,其他都支持。 Android WebView自带的缓存机制有5种: 浏览器 缓存机制 Application Cache缓存机制 ...
  • 针对校园网络中弱网元和数据中心等特性,综合考虑缓存大小、缓存决策和缓存替换算法,研究并设计一种面向校园网络安全的协作式缓存机制。高效的信息中心网络(ICN)缓存机制极大地提高了内容分发的效率,对比不同...
  • RecyclerView缓存机制

    千次阅读 2021-08-31 10:34:40
    ViewHolder是对RecyclerView上的ItemView的封装,它是RecyclerView缓存的载体。它封装了以下属性: View itemView:对应RecyclerView的子View int mPosition:View当前对应数据在数据源中的位置 int mOldPosition:...
  • Nginx缓存机制和性能优化

    千次阅读 2021-11-02 15:39:57
    Nginx缓存机制介绍 Nginx缓存机制的作用 nginx缓存机制简述 Nginx缓存支持 缓存使用 proxy_cache_path参数详解 缓存清除机制分析 被动缓存清除 缓存加载 主动清除缓存 Nginx程序运行原理分析 Nginx工作...
  • 为了降低内容中心网络的缓存内容冗余度和提高缓存内容命中率,提出一种基于节点中心性度量的缓存机制(CMC)。CMC利用控制器获取整个网络的拓扑结构和缓存空间空闲率,根据拓扑的连接关系分别计算各节点的度中心性、...
  • python的缓存机制

    千次阅读 2021-01-02 21:30:53
    python的缓存机制前言id()函数实例测试 前言 因为在创建数据时需要为数据创建内存,在销毁数据时需要释放内存,为了提高效率,Python使用了缓存机制。 什么是缓存机制呢?就是Python将一些值预先存好,当定义一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 764,051
精华内容 305,620
关键字:

缓存机制