zoukankan      html  css  js  c++  java
  • mybatis缓存(上)---一级缓存

    • 什么是一级缓存

              在日常开发过程中,经常会有相同的sql执行多次查询的情况,mybatis提供了一级缓存来优化这些查询,避免多次请求数据库。

              一级缓存在mybatis中默认是开启的并且是session级别,它的作用域为一次sqlSession会话。

    • 什么是二级缓存

              相对于一级缓存,二级缓存的作用域更广泛,它不止局限于一个sqlSession,可以在多个sqlSession之间共享,事实上,它的作用域是namespace。

              mybatis的二级缓存默认也是开启的,但由于它的作用域是namespace,所以还需要在mapper.xml中开启才能生效

    • 缓存的优先级

              通过mybatis发起的查询,作用顺序为:二级缓存->一级缓存->数据库 ,其中任何一个环节查到不为空的数据,都将直接返回结果

    • 缓存失效

              当在一个缓存作用域中发生了update、insert、delete 动作后,将会触发缓存失效,下一次查询将命中数据库,从而保证不会查到脏数据。相当于缓存只是针对select有效。

    下面通过一些示例来分别说明。(本文采用的是springboot+mybatis的方式进行测试的)

    准备条件:

    1 create table book(
    2 id int auto_increment comment '书ID',
    3 name varchar(50) comment '书名',
    4 primary key(id));
    5 
    6 
    7 insert into book(name) values('三国演义');
    8 insert into book(name) values('红楼梦');
    9 insert into book(name) values('水浒传');
    View Code

    默认引擎是InnoDB.

    一. 一级缓存

    1.实体类Book

     1 package com.example.demo.dao;
     2 
     3 public class Book {
     4     private int id;
     5     private String name;
     6 
     7     public int getId() {
     8         return id;
     9     }
    10 
    11     public void setId(int id) {
    12         this.id = id;
    13     }
    14 
    15     public String getName() {
    16         return name;
    17     }
    18 
    19     public void setName(String name) {
    20         this.name = name;
    21     }
    22 }
    View Code

    2.Controller: BookController

     1 package com.example.demo.controller;
     2 
     3 import com.example.demo.dao.Book;
     4 import com.example.demo.service.BookService;
     5 import org.springframework.beans.factory.annotation.Autowired;
     6 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
     7 import org.springframework.web.bind.annotation.GetMapping;
     8 import org.springframework.web.bind.annotation.RequestMapping;
     9 import org.springframework.web.bind.annotation.RestController;
    10 
    11 @RestController
    12 @EnableAutoConfiguration
    13 @RequestMapping("/book")
    14 public class BookController {
    15     @Autowired
    16     BookService bookService;
    17 
    18     @GetMapping("/selectBookById")
    19     Book selectBookById(){
    20       return bookService.selectBookById();
    21     }
    22 }
    View Code

    3.Service:BookService/Impl

    1 package com.example.demo.service;
    2 
    3 import com.example.demo.dao.Book;
    4 
    5 
    6 public interface BookService {
    7   Book selectBookById();
    8 }
    View Code
     1 package com.example.demo.service.impl;
     2 
     3 import com.example.demo.dao.Book;
     4 import com.example.demo.dao.mapper.BookMapper;
     5 import com.example.demo.service.BookService;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.stereotype.Service;
     8 
     9 
    10 @Service
    11 public class BookServiceImpl implements BookService {
    12 
    13     @Autowired
    14     BookMapper bookMapper;
    15     @Override
    16 
    17     public Book selectBookById() {
    18         int id=1;
    19         Book book1=bookMapper.selectBookById(id);
    20         Book book2=bookMapper.selectBookById(id);
    21         System.out.println("***********start***********");
    22         System.out.println(book1==book2);
    23         System.out.println("***********end***********");
    24         return bookMapper.selectBookById(id);
    25     }
    26 }
    View Code

    4.Mapper接口:BookMapper

    1 package com.example.demo.dao.mapper;
    2 
    3 import com.example.demo.dao.Book;
    4 import org.apache.ibatis.annotations.Mapper;
    5 
    6 @Mapper
    7 public interface BookMapper {
    8     Book selectBookById(int id);
    9 }
    View Code

     5.mapper.xml文件:BookMapper.xml

    1 <?xml version="1.0" encoding="UTF-8" ?>
    2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    3 <mapper namespace="com.example.demo.dao.mapper.BookMapper">
    4 
    5     <select id="selectBookById" resultType="com.example.demo.dao.Book">
    6         select id,name from book where id=#{id}
    7     </select>
    8 
    9 </mapper>
    View Code

    6.application.yml配置为:

     1 server:
     2   port: 8081
     3 spring:
     4   #���ݿ���������
     5   datasource:
     6     driver-class-name: com.mysql.cj.jdbc.Driver
     7     url: jdbc:mysql://localhost:3306/mytest?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
     8     username: root
     9     password: root
    10 
    11 #mybatis���������
    12 mybatis:
    13   #mapper�����ļ�
    14   mapper-locations: classpath:mapper/*.xml
    15   #type-aliases-package: com.example.demo.dao
    16   #�����շ�����
    17   configuration:
    18     log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    19 
    20   type-handlers-package: com.example.demo.dao.mapper.MyEnumHandler
    View Code

     浏览器中输入:http://localhost:8081/book/selectBookById

    查看控制台:

     从控制台可以看见创建了3次SqlSession会话,一级缓存失效。并且得到的book1和book2两个对象不等。实际上,默认是开启的一级缓存,只是我们没有添加事务管理,从而拿到了我们以为错误的结果。

    修改Service如下:

    @Transactional
        public Book selectBookById() {
            int id=1;
            Book book1=bookMapper.selectBookById(id);
            Book book2=bookMapper.selectBookById(id);
            System.out.println("***********start***********");
            System.out.println(book1==book2);
            System.out.println("***********end***********");
            return bookMapper.selectBookById(id);
        }

    仅仅是添加了@Transactional注解:

    此时控制台输出为:

    可以看到只创建了一次SqlSession会话,book2的值对应第一个Fetched SqlSession,方法的返回对应第二个Fetched SqlSession. 说明确实是从缓存拿到的数据。

    note:增删改无论加不加这个注解,都不会存在缓存现象。它们的每一次submit就认为会关闭当前SqlSession。一级缓存是和SqlSession是绑定的,只存在于SqlSession生命周期中。增删改操作都会清空一级缓存。

    note:添加@Transaction注解的原因: 由于使用了数据库连接池,默认每次查询完之后自动commit,这就导致两次查询使用的不是同一个sqlSessioin,根据一级缓存的原理,它将永远不会生效。
    当我们开启了事务,两次查询都在同一个sqlSession中,从而让第二次查询命中了一级缓存。

    note: mybatis默认的session级别一级缓存,由于springboot中默认使用了hikariCP,所以基本没用,需要开启事务才有用。但一级缓存作用域仅限同一sqlSession内,无法感知到其他sqlSession的增删改,所以极易产生脏数据

  • 相关阅读:
    ViewPager留出边 显示左右两边的视图
    Retrofit 2.0 上传文件
    android一个app打开另一个app的指定页面
    Java多线程消费者、生产者的基本思路
    Android 8.0+ 更新安装apk失败的问题
    Android 8.0+ 通知不显示的适配
    android 7.0+ FileProvider 访问隐私文件 相册、相机、安装应用的适配
    android 6.0+ 动态权限 拒绝不再询问后跳转设置应用详情页面
    ViewPager中Fragment的重复创建、复用问题
    Android源码学习(2) Handler之Looper
  • 原文地址:https://www.cnblogs.com/Hermioner/p/12641115.html
Copyright © 2011-2022 走看看