Mybatis

1. Mybatis概述

是一款优秀的持久层 半自动ORM 框架,它支持定制化SQL、存储过程以及高级映射。

MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。

MyBatis可以使用简单的XML或注解来配置和映射原生信息,将接口和Java的POJO(普通的Java对象)映射成数据库中的记录。

image-20230305223358779

Configration会去找全局配置文件,然后sesssion工厂去找sqlsession。

Sqlsession就是myBatis中最核心的了。它去加载mappedStatment。然后去执行TransAction。

2. Mybatis快速入门

  1. 创建SpringBoot项目

  2. 引入依赖

  3. <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.4</version>
     </dependency>
     <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

  4. application.properties中配置数据库连接参数

  5. 创建实体类com/codingfuture/entity/Person,并创建相应的数据库表

  6. public class Person {
        private Integer id;
        private String name;
        private Integer age;
        // getters and setters
    }

    创建com/codingfuture/mapper接口

  7. @Mapper
    public interface PersonMapper {
        List<Person> findAll();
    }

    resources中添加映射文件com.codingfuture.mapper.PersonMapper.xml

  8. <?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.codingfuture.mapper.PersonMapper">
       <select id="findAll" resultType="com.codingfuture.entity.Person">
            select *
            from person
        </select>
    </mapper>
    

3. statement详解

Mybatis的核心是SQL,一个statement代表着一个SQL,因此,statement的配置即是我们通过Mybatis操作数据库的核心。

statement分为四个标签:<insert><delete><update><select>,分别代表对数据的增删改查。

标签中定义的便是原生的SQL语句,需要新掌握的是标签上的属性:

  • id

    每个statement都有,且为必选属性,id为statement提供唯一标识,以保证该statement可以被成功定位并执行。不能重复。

  • resultType

    只有select语句有该属性,代表SQL返回结果的类型,查询用户可以指定为entity.Person类型

    比如查询数据总条数,可以指定resultType为long类型,

  • <select id="findAll" resultType="com.codingfuture.entity.Person">
            select *
            from person
        </select>
        <select id="selectTotal" resultType="java.lang.Integer">
            select count(*)
            from person
        </select>

    parameterType

    如果SQL中需要传入参数,则可以通过该属性指定参数类型,如果不指定,Mybatis会自动判断,因此该属性没有实质作用。

  • <select id="findById" parameterType="int" resultType="com.codingfuture.entity.Person">
            select *
            from person
            where id = #{id}
       </select>
    parameterType指定是什么数据类型,但是Mybatis会自动判断,故可以省略
    
    #{} 是一种占位符的形式,表示接受statement传入的参数
    如果传入的是一个参数,我们可以写任意行参代替,但是了为了可读性,还是与方法中参数表示一致

    resultMap

    只有select语句有,当SQL结果集不能自动映射到实体类属性时使用,

    比如数据库字段为person_id,而Person类中属性为personId,此时Mybatis不能自动映射,需要手动映射。

    以下为实例,id标签指定主键属性,result标签指定普通属性,column属性对应表中字段名,

    property属性对应类中属性名,autoMapping自动映射。可选

  •  <resultMap id="personMap" type="com.codingfuture.entity.Person" autoMapping="true">
            <id property="id" column="id"></id>
            <!--        <result property="age" column="age"></result>-->
            <!--        <result property="name" column="name"></result>-->
            <result property="loveColor" column="love_color"></result>
        </resultMap>
    
        <select id="findAll" resultMap="personMap">
            select *
            from person
        </select>

    insert插入

  • <insert id="insert">
        insert into person(id,name,age,love_color)
         values
        (null,"zl",26,"紫色")
    </insert>

    update更新

  • <update id="updateById">
        update person
        set name ='petrel'
        where id = 203
    </update>

    delete删除

  • <delete id="deleteById">
            delete
            from person
            where id = 204
    </delete>

    传入的参数可以有多种类型

  • 基本类型( int,String,double,long,date……) 在SQL中获取这类请求参数可以使用#{}表达式,{}中可以填任意字符串,但应该保证可读性,比如:

    <select id="findAllById" resultType="com.codingfuture.entity.Person">
            select * from person where id = #{ids}
    </select>
    #{ids} 内部名字id自定义,只是一个占位符
    但是也可以指定参数
    List<Person> selectByAge(@Param("age1") int a, @Param("age2") int b);
    
      <select id="selectByAge" resultMap="personMap">
            select *
            from person
            where age >= #{age1}
              and age &lt;= #{age2}
        </select>

    POJO 即传入实体类,比如一个Person:

  • <insert id="insert" parameterType="com.codingfuture.entity.Person">
            insert into person (id, name, age, love_color)
            values (null, #{name}, #{age}, #{loveColor})
        </insert>
    注意#{内部字段名是POJO实体类的成员变量名称}
    
    
    多个参数传递问题 其中有一个参数时java对象,我们需要指定时对象的哪项属性,防止与其他类型参数进行混淆
    int i = personMapper.updateById(1, person);
    
      <update id="updateById">
            update person
            set name       = #{person.name},
                age        = #{person.age},
                love_color = #{person.loveColor}
            where id = #{id}
    
     </update> 

4.配置:

mybatis的settings配置很丰富:

设置名描述有效值默认值
cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true | falsetrue
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true | falsefalse
aggressiveLazyLoading开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。true | falsefalse (在 3.4.1 及之前的版本中默认为 true)
multipleResultSetsEnabled是否允许单个语句返回多结果集(需要数据库驱动支持)。true | falsetrue
useColumnLabel使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。true | falsetrue
useGeneratedKeys允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。true | falseFalse
autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。NONE, PARTIAL, FULLPARTIAL
autoMappingUnknownColumnBehavior指定发现自动映射目标未知列(或未知属性类型)的行为。NONE: 不做任何反应WARNING: 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARNFAILING: 映射失败 (抛出 SqlSessionException)NONE, WARNING, FAILINGNONE
defaultExecutorType配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。SIMPLE REUSE BATCHSIMPLE
defaultStatementTimeout设置超时时间,它决定数据库驱动等待数据库响应的秒数。任意正整数未设置 (null)
defaultFetchSize为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。任意正整数未设置 (null)
defaultResultSetType指定语句默认的滚动策略。(新增于 3.5.2)FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置)未设置 (null)
safeRowBoundsEnabled是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。true | falseFalse
safeResultHandlerEnabled是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。true | falseTrue
mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。true | falseFalse
localCacheScopeMyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。SESSION | STATEMENTSESSION
jdbcTypeForNull当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。OTHER
lazyLoadTriggerMethods指定对象的哪些方法触发一次延迟加载。用逗号分隔的方法列表。equals,clone,hashCode,toString
defaultScriptingLanguage指定动态 SQL 生成使用的默认脚本语言。一个类型别名或全限定类名。org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
defaultEnumTypeHandler指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5)一个类型别名或全限定类名。org.apache.ibatis.type.EnumTypeHandler
callSettersOnNulls指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。true | falsefalse
returnInstanceForEmptyRow当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2)true | falsefalse
logPrefix指定 MyBatis 增加到日志名称的前缀。任何字符串未设置
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未设置
proxyFactory指定 Mybatis 创建可延迟加载对象所用到的代理工具。CGLIB | JAVASSISTJAVASSIST (MyBatis 3.3 以上)
vfsImpl指定 VFS 的实现自定义 VFS 的实现的类全限定名,以逗号分隔。未设置
useActualParamName允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1)true | falsetrue
configurationFactory指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3)一个类型别名或完全限定类名。未设置
shrinkWhitespacesInSql从SQL中删除多余的空格字符。请注意,这也会影响SQL中的文字字符串。 (新增于 3.5.5)true | falsefalse
defaultSqlProviderTypeSpecifies an sql provider class that holds provider method (Since 3.5.6). This class apply to the type(or value) attribute on sql provider annotation(e.g. @SelectProvider), when these attribute was omitted.A type alias or fully qualified class nameNot set
  • Mybatis默认支持别名:

    别名映射的类型
    _bytebyte
    _longlong
    _shortshort
    _intint
    _integerint
    _doubledouble
    _floatfloat
    _booleanboolean
    stringString
    byteByte
    longLong
    shortShort
    intInteger
    integerInteger
    doubleDouble
    floatFloat
    booleanBoolean
    dateDate
    decimalBigDecimal
    bigdecimalBigDecimal
  • 自定义别名:

  • 使用Mapper代理的形式开发,需要编写Mapper接口

    • 要么使用@Mapper接口标注在每一个Mapper接口上。

    • 要么在启动类上使用@MapperScan(basePackages = "com.codingfuture.mapper")进行全包扫描。

  • 编写Mapper接口对应的xml映射文件。注意:映射文件目录要与Mapper接口包对应

  • 可以在启动类上添加注解,来批量扫描Mapper接口,从而避免使用@Mapper注解。

  • @SpringBootApplication
    @MapperScan(basePackages = "com.codingfuture.mapper")
    public class MybatisDemoApplication {
    
        public static void main(String[] args) {
    
            SpringApplication.run(MybatisDemoApplication.class, args);
        }
    
    }

    Spring Boot项目默认使用logback作为日志框架,可以设置日志等级来输出更多信息,比如Mybatis所执行的SQL

  • logging.level.com.codingfuture.mybatis_demo=debug

  • Spring Boot项目指定映射文件路径(指定resource根目录下mapper中的所有Mapper.xml文件)

  • mybatis.mapper-locations=classpath:mapper/*Mapper.xml

  • Mybatis中的配置都可以在application.properties中完成,包括数据库连接池的配置、驼峰配置、别名配置等。

  • # 下划线转驼峰  
    mybatis.configuration.map-underscore-to-camel-case=true

  • <select id="findAll" resultType="com.codingfuture.entity.Person">
            select *
            from person
     </select>
    // 可以不必再指定resultMap

    # 别名
    mybatis.type-aliases-package=com.codingfuture.entity

  • <select id="findAll" resultType="person">
            select *
            from person
     </select>

    主键返回(useGeneratedKeys)

  • mybatis.configuration.use-generated-keys=true

    package com.codingfuture.entity;
    public class Cat {
        private String id;
        private String name;
        private Integer pId;
    
       getter&&setter
     
    }
    
    <!--   personMapper-->
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
            insert into person (id, name, age, love_color)
            values (null, #{name}, #{age}, #{loveColor})
      </insert>
    
    public interface CatMapper {
        int insert(Cat cat);
    }
    
    <!--    catMapper-->
      <insert id="insert">
            insert into cat (id, name, p_id)
            values (#{id}, #{name}, #{pId})
     </insert>

5. 动态SQL

  • 什么是动态sql Mybatis可以通过语法的判断对sql进行灵活封装,拼接。

  • 需求:

    • 没有条件,select * from person

    • 查询id=1的姓名 select * from person where id = 1

    • 查询name=zs的姓名 select * from person where name = ‘’zs“

    • 查询id=1的并age=23的。select * from person where id = 1 and age = 23

    • 会发现我们需要写很多种可能的sql语句。不灵活

    • 动态sql就是解决这个问题的。


  • if标签和where标签

  • <select id="find" resultType="com.codingfuture.entity.Person">
            select *
            from person
            <where>
                <if test="id!=null">
                    and id = #{id}
                </if>
                <if test="name!=null a">
                    and name = #{name}
                </if>
                <if test="age!=null">
                    and age = #{age}
                </if>
                <if test="loveColor!=null">
                    and love_color liKe "%"#{loveColor}"%"
                </if>
            </where>
        </select>
    
    
    注意:
    1.like这块 的字符拼接如下两种方式都可以,
    and love_color liKe "%"#{loveColor}"%" 推荐使用这种方式
    and love_color liKe "%${loveColor}%"  但是$的形式,是字符串拼接的,会出现sql注入问题。 
    2.注释使用xml的注释,不能使用sql语句注释
    public interface PersonMapper {
     ...
         List<Person> find(Person person);
    ...
    }

    sql片段 sql片段可以让程序员写的sql使用率更高,也就是说可重用性更高。

  • 可以用sql标签定义一些必须查询列,提取出来。然后用include标签引入
    <sql id="all">
            id
            ,name,age
    </sql>
    
    <select id="findAll" resultMap="personMap">
            select
            <include refid="all"/>
            ,love_color
            from person
     </select>

    foreach标签

    删除:delete

  • 写法一:
    <delete id="deleteByIds">
       
                <!-- collection:指定输入集合或者数组的参数名称 集合就是list。数组就是array -->
                <!-- item:声明遍历出的参数变量 -->
                <!-- open:遍历开始时需要拼接的内容 -->
                <!-- close:遍历结束时需要拼接的内容 -->
                <!-- separator:遍历出的参数变量之间需要拼接的参数 ,delete from person where id in ( 1,2,3)-->
            delete from person where id in (
            <foreach collection="array" item="deleteid" separator=",">
                ${deleteid}
            </foreach>
            )
        </delete>
    
    写法二:
    <delete id="deleteByIds">
            delete from person
            <foreach collection="array" item="deleteid" open="where id in (" close=")" separator=",">
                ${deleteid}
            </foreach>
        </delete>
    
    混合判断:delete from person where id in (1,2)
    <delete id="deleteByIds">
        delete from person
        <where>
            <if test="list!=null and list.size>0">
                <foreach collection="list" item="id" open="and id in ( " close=" ) " separator=",">
                    #{id}
                </foreach>
            </if>
            <if test="list==null or list.size==0">
                and 1d = 2
            </if>
        </ where>
    </delete>

    set标签

    相当于update的set关键字,会帮我们去掉最后一个逗号

    更新:update

  • <update id="update">
            update person
            <set>
                <if test="person.name!=null">
                    name = #{person.name},
                </if>
                <if test="person.age!=null">
                    age = #{person.age},
                </if>
                <if test="person.loveColor!=null">
                    love_color = #{person.loveColor},
                </if>
            </set>
            where id = #{id}
    
        </update>

    传递多个参数问题

  • <update id = "update">
      update person 
      <set>
        	<if test="person.name!=null">
      	  name = #{person.name},
      		<if test="person.age!=null">
      	  name = #{person.age},
      	  <if test="person.loveColor!=null">
      	  love_color = #{person.loveColor},
      </set>
      where id = #{id}
    </update>

6. 多表映射

需求一

需求:查询订单信息,关联查询购买该订单的用户信息。

image-20230307223018531

需求:查询订单信息,关联查询购买该订单的用户信息。

sql:

SELECT * FROM `order` o, `user` u WHERE o.user_id = u.id;

image-20230307225848117

多表查询涉及到重名的字段,可以通过sql中的别名解决

	-- 需求:查询订单信息,关联查询购买该**订单**的用户信息。
SELECT
	o.id order_id,
	o.create_time create_time,
	o.user_id user_id,
	u.username username,
	u.PASSWORD PASSWORD 
FROM
	`order` o,
	`user` u 
WHERE
	o.user_id = u.id
	
	-- 需求:查询订单信息,关联查询购买该**订单**的用户信息。

SELECT 
o.id order_id,
o.create_time create_time,
o.user_id  user_id,
u.username username,
u.`password` `password`
FROM 
`order` o
LEFT JOIN `user`  u
ON o.user_id = u.id

查询出正确且合适的结果集后,就可以进行映射的配置了:

User类。用户信息

public class User {
    private Integer id;
    private String username;
    private String password;
		//getter setter
}

 Order类。订单

public class Order {
    private Integer id;
    private Date createTime;
    private Integer userId;
    //private User user;//后加 代表订单所属用户
		//getter setter
}

//  在多对一的时候,我们通常将一的一方作为多的一方的属性
//  这样是为了保证下方的List集合的泛型

 创建OderMapper接口和OrderMapper.xml

public interface OrderMapper {
    List<Order> findOrdersWithUser();
}
//  这里泛型定义成Order是因为我们将User的相关信息定义成了Order类的属性。
//  在多对一的时候,我们通常将一的一方作为多的一方的属性

<resultMap id="findOrdersWithUser" type="com.codingfuture.entity.Order" autoMapping="true">
        <id column="order_id" property="id"/>
        <result column="create_time" property="createTime"/>
        <result column="user_id" property="userId"/>
        <association property="user" javaType="User" autoMapping="true">
            <id column="user_id" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
        </association>

    </resultMap>

    <select id="findOrdersWithUser" resultMap="findOrdersWithUser">
        SELECT o.id          order_id,
               o.create_time create_time,
               o.user_id     user_id,
               u.username    username,
               u.`password`  `password`
        FROM `order` o
                 LEFT JOIN `user` u
                           ON o.user_id = u.id
    </select>

<association>代表单一的关联,在多对一. 或. 一对一的关系中使用,注意需要指定javaType属性。

测试类:

@Autowired
 private OrderMapper orderMapper; 
@Test
    void findOrdersWithUser() {
        List<Order> ordersWithUser = orderMapper.findOrdersWithUser();
        for (Order order : ordersWithUser) {
            System.out.println(order);
        }
    }

注意:

我们想偷个懒,标注红线的地方的映射我们想省略,

image-20230307230314166

# 下划线转驼峰
mybatis.configuration.map-underscore-to-camel-case=true

此外:我们还有另外一种做法:这里我们需要引入一个新的概念DTO

数据传输对象(DTO)(Data Transfer Object),是一种设计模式之间传输数据的软件应用系统。数据传输目标往往是数据访问对象从数据库中检索数据。数据传输对象与数据交互对象或数据访问对象之间的差异是一个以不具有任何行为除了存储和检索的数据(访问和存取器)。

  • 新建包dto,并创建 OrderAndUserDTO dto

  • public class OrderAndUserDTO {
        private Integer orderId;
        private Date createTime;
        private Integer userId;
        private String username;
        private String password;
       // getter && sertter..
    }

  • 在接口OrderMapper添加新方法

  • public interface OrderAndUserDtoMapper {
        List<OrderAndUserDTO> findOrderAndUser();
    }

  • OrderMapper.xml中增加如下配置

  • <resultMap id="findOrderAndUser" type="com.codingfuture.dto.OrderAndUserDto" autoMapping="true">
            <id column="order_id" property="orderId"/>
        </resultMap>
        <select id="findOrderAndUser" resultMap="findOrderAndUser">
            SELECT o.id          order_id,
                   o.create_time create_time,
                   o.user_id     user_id,
                   u.username    username,
                   u.`password`  `password`
            FROM `order` o
                     LEFT JOIN `user` u
                               ON o.user_id = u.id
        </select>

7. 查询优化

7.1 延迟加载

什么是延迟加载
  • 根据主表信息去关联查询从表信息时,如果需要从表信息,再去数据库进行查询,如果不需要,则使用代理对象。

    延迟加载就是懒加载,也就是按需加载。

  • Mybatis中的association标签和collection标签具有延迟加载的功能。

需求:

查询车辆信息,按需加载用户信息

实操:

PersonMapper接口中定义方法

public interface PersonMapper {
   Person findById(Integer id);
}

CarMapper接口中定义方法

public interface CarMapper {
    Car findById(Integer id);
}

 定义车的实体/dto

public class Car {
    private Integer id;
    private String name;
    private Integer age;
    private Integer pId;
    private Person person;
    .....
}

 在PersonMapper.xml中编写一个statement去查询人的信息:

<select id="findById" resultType="com.codingfuture.entity.Person">
        select * from person  where id = #{id}
   </select>

CarMapper.xml中编写一个statement去查询车的信息:

<resultMap id="carMapper" type="com.codingfuture.entity.Car" autoMapping="true">
        <id property="id" column="id"/>
        <!--        <result column="name" property="name"/>-->
        <!--        <result column="age" property="age"/>-->
        <!--        <result column="p_id" property="pId"/>-->
        <association property="person" select="com.codingfuture.mapper.PersonMapper.findById"
                     column="p_id" autoMapping="true">
        </association>
    </resultMap>

    <select id="findCarById" resultMap="carMapper">
        select *
        from car
        where id = #{id}
    </select>

7.2 缓存

缓存简介

Mybatis包含一个非常强大的查询缓存特性,它可以非常方便配置和定制。缓存可以极大的提升查询效率。

例如:每个用户登入的页面的菜单功能选项都是固定的,点击每个选项都需要去数据库中查询数据,那么对于所有用户来说,数据都是一样的,那么我们就没必要每次点击菜单功能选项都去查询数据库,那样效率会很低,用户很多的时候,数据库服务器负担就会很严重。

所以我们就需要用到缓存。

Mybatis的查询分为:

  • 一级缓存指的是sqlsession级别的。(本地缓存)

    • 一级缓存只会在同一个sqlsession之间共享,多个sqlsession之间的一级缓存是互相独立的,默认一直开启,没法关闭。

    • 与数据库同一次会话期间查询到的数据会放在本地缓存。以后如果需要获取相同数据,直接从缓存中拿,没必要再去查数据库。

  • 二级缓存指的是mapper(namespace)级别的。(全局缓存)

    • 二级缓存只会在同一个namespace下的mapper映射文件之间共享。

image-20230308222424737

一级缓存

Mybatis默认支持一级缓存。

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

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

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

一级缓存失效:
  1. sqlSession不同:相同数据在sqlSession域中会被共享,不同sqlSession域之间数据不会共享

  2. sqlSession相同:查询条件不同,(一级缓存中还没有这个要查询的数据)

  3. sqlSession相同:两次查询之间,增加了 CRUD操作(有可能CRUD会影响当前数据)

  4. sqlSession相同:手动清除了一级缓存数据,(缓存清空)

二级缓存

二级缓存指的是mapper(namespace)级别的。一个namespace对应一个二级缓存

工作机制:
  1. 一个会话,查询一条数据,这个数据会被放在当前会话的一级缓存中

  2. 如果会话关闭,一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,可以参考二级缓存

  3. sqlSession--->

    不同namespace查出的数据会放在自己的对应缓存中(map)

8 Mybatis执行流程

image-20230308230712456

Configration会去找全局配置文件mybatis.xml,然后sesssion工厂去找sqlsession。

我们写servlet目前是为了接收前端请求和连接数据库,访问数据,

那么servlet和数据库的连接也算是请求数据和响应数据。

Sqlsession就是myBatis中最核心的了。它去加载mappedStatment。然后去执行TransAction。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gao_xu_sheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值