Mybatis

文章目录

  • 前言
  • 1 Mybatis学习
    • 1.1 根据ID查询数据
      • 1.1.1 编辑测试方法
      • 1.1.2 编辑接口方法
      • 1.1.3 编辑映射文件
    • 1.2 完成用户入库操作
      • 1.2.1 编辑测试类
      • 1.2.2 编辑Mapper接口
      • 1.2.3 编辑Mapper映射文件
    • 1.3 作业练习
      • 1.3.1 编辑测试类方法
      • 1.3.2 编辑Mapper接口方法
      • 1.3.3 编辑Mapper映射文件
    • 1.4 Map集合封装数据
      • 1.4.1 编辑测试方法
      • 1.4.2 编辑Mapper接口方法
      • 1.4.3 编辑Mapper 映射文件
    • 1.5 @Param注解
      • 1.5.1 需求说明
      • 1.5.2 编辑测试类
      • 1.5.3 编辑Mapper接口
      • 1.5.4 编辑Mapper映射文件
    • 1.6 Mybatis 模糊查询写法
      • 1.6.1 编辑测试方法
      • 1.6.2 编辑接口方法
      • 1.6.3 编辑映射文件
    • 1.7 Mybatis属性优化
      • 1.7.1 别名包用法
      • 1.7.2 Sql标签用法
    • 1.8 Mybatis中集合参数用法 array/list
      • 1.8.1 Array类型的参数说明
      • 1.8.2 测试代码
      • 1.8.3 编辑Mapper接口
      • 1.8.4 编辑Mapper 映射文件
    • 1.9 Mybatis中集合参数用法Map封装
      • 1.9.1 测试代码
      • 1.9.2 编辑Mapper接口
      • 1.9.3 编辑Mapper映射文件
  • 2.动态Sql
    • 2.1 动态Sql-where条件
      • 2.1.1 编辑测试类
      • 2.1.2 编辑Mapper接口
      • 2.1.3 编辑Mapper 映射文件
    • 2.2 动态Sql-Set标签
      • 2.2.1 编辑测试类
      • 2.2.2 编辑Mapper接口
      • 2.2.3 编辑Mapper.xml映射文件
    • 2.3 动态Sql-choose、when、otherwise
      • 2.3.1 编辑测试类
      • 2.3.2 编辑接口
      • 2.3.3 编辑xml映射文件
    • 2.4 ResultMap语法
      • 2.4.1 封装数据表-POJO对象
      • 2.4.2 准备Mapper接口/映射文件
      • 2.4.3 需求说明
      • 2.4.4 案例测试
      • 2.4.5 编辑Mapper接口
      • 2.4.6 编辑xml映射文件
    • 2.5 驼峰映射规则
    • 2.5.1 业务说明
  • 3 Mybatis 关联关系
    • 3.1 常见关联关系
    • 3.2 一对一映射
      • 3.2.1 创建表
      • 3.2.2 测试准备
      • 3.2.3 关于一对一业务说明
    • 3.2.4 关联查询方式
      • 3.2.5 编辑测试类
      • 3.2.6 编辑EmpMapper接口
      • 3.2.7 编辑EmpMapper.xml映射文件
      • 3.2.8 连接查询
    • 3.3 一对多查询
      • 3.3.1 业务需求
      • 3.3.2 编辑测试代码
      • 3.3.3 编辑Mapper接口
      • 3.3.4 编辑DeptMapper.xml文件
    • 3.4 Mybatis的注解形式
    • 3.5 @MapperScan
  • 4.1 Mybatis缓存实现
    • 4.1.1 缓存机制
    • 4.2 Mybatis-一级缓存
      • 4.2.1 一级缓存说明
      • 4.2.2 一级缓存测试说明
    • 4.3 Mybatis-二级缓存
      • 4.3.1 二级缓存说明
      • 4.3.2 标识二级缓存
      • 4.3.3 Mybatis二级缓存测试
      • 4.3.4 关于对象序列化问题
    • 4.4 关于Mybatis一二级缓存的说明
    • 4.5关于缓存的作用域问题
    • 4.6 Mybatis底层实现原理(了解)
  • 数据自动回显
  • 常用注解

前言

本人发布的一系列资料都是学习备份使用,以及方便日后复习,随着技术的不断提升,每个文章都会持续添加内容,或者是扩展文章,本是秉承着分享的心态,互相学习,互相提升,也希望提出更好的意见,以及学习思路,欢迎留言,欢迎评论,谢谢!!

1 Mybatis学习

1.1 根据ID查询数据

1.1.1 编辑测试方法

 /**
     * 业务需求:  根据ID查询数据
     * 参数:  id = 1
     */
    @Test
    public void test02(){
        int id = 1;
        User user = userMapper.findUserById(id);
        System.out.println(user);
    }

1.1.2 编辑接口方法

User findUserById(int id);

1.1.3 编辑映射文件

 <!--根据id查询用户数据
        语法: 动态获取数据 #{属性名称}
        #号效果: 有预编译的效果  防止Sql注入攻击问题
                所以以后取值使用#号
    -->
    <select id="findUserById" resultType="com.jt.pojo.User">
        select * from demo_user where id= #{id}
    </select>

1.2 完成用户入库操作

1.2.1 编辑测试类

/**
     * 实现用户入库操作
     */
    @Test
    public void saveUser(){
        User user = new User();
        user.setName("元旦快乐").setAge(2022).setSex("女");
        //如果需要返回值  则int接收
        int rows = userMapper.saveUser(user);
        //如果不需要返回值 则void标识
        //userMapper.saveUser(user);
        System.out.println("入库成功:影响:"+rows+"行");
    }

1.2.2 编辑Mapper接口

 int saveUser(User user);

1.2.3 编辑Mapper映射文件

<!--
        规则:
             1.如果接口方法中,int类型的返回值,则入库之后,mybatis自动回传数据
             2.如果接口中传递的是POJO对象.则通过#{属性}取值
        大小问题:
              1.windows系统中程序运行不区分大小写.
              2.Linux系统 严格区分大小写.
              3.程序猿口头禅:  我在我本机上没问题呀!!!!
    -->
    <insert id="saveUser">
        insert into demo_user(id,name,age,sex) values (null,#{name},#{age},#{sex})
    </insert>

1.3 作业练习

1.3.1 编辑测试类方法

/**
     * 3.修改操作  将name="元旦快乐" 改为age=17,sex=男
     */
     @Test
     public void updateUser(){
         User user = new User();
         user.setName("元旦快乐").setAge(17).setSex("男");
         userMapper.updateUser(user);
         System.out.println("修改操作成功!!!");
     }

     //4.删除操作  将name="春节快乐"的数据删除
     @Test
     public void deleteUser(){
         String name = "春节快乐";
         userMapper.deleteUser(name);
         System.out.println("删除成功!!!");
     }

1.3.2 编辑Mapper接口方法

    void updateUser(User user);

    void deleteUser(String name);

1.3.3 编辑Mapper映射文件

	<update id="updateUser">
        update demo_user set age=#{age}, sex=#{sex}
        where name=#{name}
    </update>

    <delete id="deleteUser">
        delete from demo_user where name=#{name}
    </delete>

1.4 Map集合封装数据

1.4.1 编辑测试方法

 /**
     * 业务: 查询age> 18岁  and  age <100的用户.
     * 知识点:
     *      1.mybatis的参数可以是基本类型或者字符串.
     *      2.如果遇到多个参数,应该使用对象(POJO)进行封装.
     *      3.如果通过pojo封装不方便.则使用功能最为强大的Map进行封装
     *      4.Mybatis的接口方法中只允许传递单值
     */
    @Test
    public void testFindUserByAge(){
        Map<String,Object> map = new HashMap<>();
        map.put("minAge",18);
        map.put("maxAge",100);
        List<User> userList = userMapper.findUserByAge(map);
        System.out.println(userList);
    }

1.4.2 编辑Mapper接口方法

List<User> findUserByAge(Map<String, Object> map);

1.4.3 编辑Mapper 映射文件

<!--
        知识点1: 通过 #{参数名称/对象中的属性/Map中的key}
        知识点2: xml文件中有些字符需要转义
                > &gt;   < &lt;
                & &amp;
    -->
    <select id="findUserByAge" resultType="com.jt.pojo.User">
        select * from demo_user where age>#{minAge} and age &lt; #{maxAge}
    </select>

1.5 @Param注解

1.5.1 需求说明

说明: 根据下列的代码,不能非常直观去了解业务. 能否优化该操作.

List<User> findUserByAge(Map<String, Object> map);

1.5.2 编辑测试类

 @Test
    public void testFindUserByAge2(){
        int minAge = 18;
        int maxAge = 100;
        List<User> userList = userMapper.findUserByAge2(minAge,maxAge);
        System.out.println(userList);
    }

1.5.3 编辑Mapper接口

	//如果参数是多值,则需要封装为单值Map
    //@Param将参数封装为Map集合
    List<User> findUserByAge2(@Param("minAge") int minAge,
                              @Param("maxAge") int maxAge);

1.5.4 编辑Mapper映射文件

 	<select id="findUserByAge2" resultType="com.jt.pojo.User">
        select * from demo_user where age>#{minAge} and age &lt; #{maxAge}
    </select>

1.6 Mybatis 模糊查询写法

1.6.1 编辑测试方法

/**
     * 需求: 查询name中 包含"君"字的数据
     * Sql:  where name like "%君%"
     */
    @Test
    public void findByLike(){
        String key = "君";
        List<User> userList = userMapper.findByLike(key);
        System.out.println(userList);
    }

1.6.2 编辑接口方法

List<User> findByLike(String key);

1.6.3 编辑映射文件

  <!--
        知识点1: 通过 #{参数名称/对象中的属性/Map中的key}
        知识点2: xml文件中有些字符需要转义
                > &gt;   < &lt;
                & &amp;
    -->
    <select id="findUserByAge" resultType="com.jt.pojo.User">
        select * from demo_user where age>#{minAge} and age &lt; #{maxAge}
    </select>

1.7 Mybatis属性优化

1.7.1 别名包用法

其中resultType中的属性com.jt.pojo.User 定义别名.简化其操作.

 	<select id="findByLike" resultType="com.jt.pojo.User">
        select * from demo_user where name like "%"#{key}"%"
    </select>
  1. 标识注解
    Mybatis_第1张图片
  2. 使用别名
    在这里插入图片描述
  3. 定义别名包 定义别名包之后,以后的数据只需要写类名即可,使用时会自动的拼接前缀
#3.配置Mybatis
mybatis:
  #定义别名包
  type-aliases-package: com.jt.pojo

1.7.2 Sql标签用法

<!--Sql标签作用: 抽取公共的部分,可以被其它的Sql引用-->
    <sql id="findColumn">
        select id,name,age,sex from demo_user
    </sql>

    <select id="findByLike" resultType="User">
        <include refid="findColumn"/> where name like "%"#{key}"%"
    </select>

1.8 Mybatis中集合参数用法 array/list

1.8.1 Array类型的参数说明

说明: 一般业务逻辑可能会用到array进行数据的封装. 问题: xml映射文件中如何解析数组
格式如下: Integer[] ids = {1,3,4,5,6};

1.8.2 测试代码

/**
     * 业务说明: 集合参数的用法
     * 需求: 查询id=1,3,4,5,6的数据
     * Sql:  where id in (1,3,4,5,6)
     */
    @Test
    public void findIn(){
        Integer[] ids = {1,3,4,5,6};
        List<User> list = userMapper.findIn(ids);
        System.out.println(list);
    }

1.8.3 编辑Mapper接口

	List<User> findIn(Integer[] ids);

1.8.4 编辑Mapper 映射文件

<!--
        需求: Integer[] ids 中的数据一个一个取出来.拼接Sql
        知识点: mybatis中如何遍历数组
        foreach标签用法:
            1. collection:需要遍历的集合的类型
                1.1 数组类型  关键字:array
                1.2 list类型 关键字:list
                1.3 map类型  关键字:Map中的key
            2. open/close 循环开始和结束标签,一般自己写
            3. item 遍历数据的变量名称
            4. separator 参数之间的分隔符
    -->
    <select id="findIn" resultType="User">
        select * from demo_user where id in (
            <foreach collection="array" item="id" separator=",">
                #{id}
            </foreach>
        )
    </select>

1.9 Mybatis中集合参数用法Map封装

1.9.1 测试代码

@Test
    public void findInMap(){
        //准备2个集合,测试map集合封装
        Integer[] ids1 = {1,3,4,5,6};
        Integer[] ids2 = {1,3,4,5,6};
        List<User> list = userMapper.findInMap(ids1,ids2);
        System.out.println(list);
    }

1.9.2 编辑Mapper接口

 List<User> findInMap(@Param("ids1") Integer[] ids1,
                         @Param("ids2") Integer[] ids2);

1.9.3 编辑Mapper映射文件

 	<!--参数传递是Map集合,所以关键字使用key-ids1 -->
    <select id="findInMap" resultType="User">
        select * from demo_user where id in (
            <foreach collection="ids1" item="id" separator=",">
                #{id}
            </foreach>
        )
    </select>

2.动态Sql

2.1 动态Sql-where条件

2.1.1 编辑测试类

package com.jt;

import com.jt.mapper.UserMapper2;
import com.jt.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class TestMybatis2 {

    @Autowired
    private UserMapper2 userMapper;

    /**
     * 需求: 根据用户不为null的属性充当where条件
     */
    @Test
    public void testSqlWhere(){
        User user = new User();
        user.setAge(3000).setSex("男");
        List<User> userList = userMapper.findSqlWhere(user);
        System.out.println(userList);
    }

}

2.1.2 编辑Mapper接口

@Mapper //将接口的代理对象交给Spring容器管理
public interface UserMapper2 {
    List<User> findSqlWhere(User user);
}

2.1.3 编辑Mapper 映射文件

<?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.jt.mapper.UserMapper2">

    <!--
        问题说明: 前端数据传递时可能会有null数据.
                如果数据为null则不能充当where条件
        解决方案: 动态Sql实现
        语法:
            <if test="判断条件"> id = #{id}</if>
                true:   则拼接标签内容
                false:  则不拼接标签内容
           <where>标签: 去除where后边多余的and/or
    -->
    <select id="findSqlWhere" resultType="User">
        select * from demo_user
            <where>
                <if test="id != null"> id = #{id}</if>
                <if test="name !=null">and name = #{name}</if>
                <if test="age !=null"> and age = #{age}</if>
                <if test="sex !=null"> and sex = #{sex}</if>
            </where>
    </select>
</mapper>

2.2 动态Sql-Set标签

2.2.1 编辑测试类

/**
     * 需求: 修改id=1 的数据 name="北极熊",age=4000 sex="男"
     */
    @Test
    public void testUpdateUser(){
        User user = new User();
        user.setId(1).setAge(5000);
        userMapper.updateUser(user);
        System.out.println("更新成功!!!");
    }

2.2.2 编辑Mapper接口

 void updateUser(User user);

2.2.3 编辑Mapper.xml映射文件

 <!--根据对象中不为null的属性 当做set条件
        语法: set标签 去除多余1,-->
    <update id="updateUser">
        update demo_user
            <set>
                <if test="name !=null">name=#{name},</if>
                <if test="age !=null"> age=#{age},</if>
                <if test="sex !=null"> sex=#{sex},</if>
            </set>
            where id = #{id}
    </update>

2.3 动态Sql-choose、when、otherwise

2.3.1 编辑测试类

 /**
     * 如果name有值,则根据name查询.
     * 如果name没有值,则根据age查询.
     * 如果name/age都没有值,则根据sex查询
     */
    @Test
    public void testChoose(){
        User user = new User();
        user.setSex("男");
        List<User> userList = userMapper.findChoose(user);
        System.out.println(userList);
    }

2.3.2 编辑接口

List<User> findChoose(User user);

2.3.3 编辑xml映射文件

<!--
     * 如果name有值,则根据name查询.
     * 如果name没有值,则根据age查询.
     * 如果name/age都没有值,则根据sex查询
       语法类似: if->else-if->else
    -->
    <select id="findChoose" resultType="User">
        select * from demo_user
        <where>
            <choose>
                <when test="name !=null"> name=#{name}</when>
                <when test="age !=null"> age = #{age}</when>
                <!--必须保证sex必须有值 -->
                <otherwise>sex=#{sex}</otherwise>
           </choose>
       </where>
   </select>

2.4 ResultMap语法

2.4.1 封装数据表-POJO对象

  1. 创建dog表
    Mybatis_第2张图片
  2. 编辑POJO对象
package com.jt.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Dog implements Serializable {

    private Integer dogId;
    private String  dogName;
    private Integer age;

}

2.4.2 准备Mapper接口/映射文件

Mybatis_第3张图片

2.4.3 需求说明

1.经过demo_user测试,发现如果字段名称与对象属性的名称一致,Mybatis可以实现自动化的映射
2.如果遇到字段名称与属性的名称不一致的现象,则mybatis如何映射!!!

2.4.4 案例测试

package com.jt;

import com.jt.mapper.DogMapper;
import com.jt.pojo.Dog;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class TestMybatis3 {

    @Autowired
    private DogMapper dogMapper;

    @Test
    public void testFindAll(){
        List<Dog> dogList = dogMapper.findAll();
        System.out.println(dogList);
    }
}

2.4.5 编辑Mapper接口

@Mapper
public interface DogMapper {

    List<Dog> findAll();
}

2.4.6 编辑xml映射文件

<?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.jt.mapper.DogMapper">

    <!--
        规则:
            1.如果数据库中的表字段名称与POJO属性的名称不一致
            则mybatis无法自动完成映射.
            2.Mybatis提供了一个属性resultMap(使用最多的).
              支持用户手动映射.
    -->
    <select id="findAll" resultMap="dogRM">
        select * from dog
    </select>

    <!--
        属性说明:  id="唯一标识,不能重复"
                  type="映射的POJO对象的类型"
        简化说明:  如果字段名称与属性名称一致则可以省略
                  autoMapping="true" 开启自动映射
    -->
    <resultMap id="dogRM" type="Dog" autoMapping="true">
        <!--1.标识主键-->
        <id column="dog_id" property="dogId"/>
        <!--2.映射结果集-->
        <result column="dog_name" property="dogName"/>
        <!--<result column="age" property="age"/>-->
    </resultMap>
</mapper>

2.5 驼峰映射规则

2.5.1 业务说明

Mybatis中的结果集的字段名称如果与属性的名称满足驼峰映射的规则. 如果开启驼峰映射.,则可以实现自动化的映射.

字段: dog_id, dog_name
属性: dogId, dogName 满足驼峰规则.
配置信息:

#3.配置Mybatis
mybatis:
  #定义别名包
  type-aliases-package: com.jt.pojo
  #将所有的映射文件全部加载
  mapper-locations: classpath:/mappers/*.xml
  #开启驼峰映射
  configuration:
    map-underscore-to-camel-case: true

3 Mybatis 关联关系

3.1 常见关联关系

思路:看问题从一头出发看向另一头

  1. 一对一 一个员工对应一个部门
  2. 一对多 一个部门下对应多个员工
  3. 多对一 本质是一对一
  4. 多对多 老师和学生 双向的一对多
    一个老师对应多个学生.
    一个学生对应多个老师.

3.2 一对一映射

3.2.1 创建表

表名 dept
字段: dept_id, int 主键 自增
dept_name, varchar(40)

表名 emp
字段: emp_id, int 主键 自增
emp_name, varchar(40)
dept_id int

造表数据
Mybatis_第4张图片
Mybatis_第5张图片

3.2.2 测试准备

根据表 创建POJO/Mapper接口/xml映射文件
Mybatis_第6张图片

3.2.3 关于一对一业务说明

表关系: 一个员工对应一个部门.
需求: 将部门信息与员工信息绑定.
如图所示:
Mybatis_第7张图片

3.2.4 关联查询方式

  1. 笛卡尔积的形式
  2. 连接查询 左连接,右连接,内连接
  3. 子查询

3.2.5 编辑测试类

package com.jt;

import com.jt.mapper.DeptMapper;
import com.jt.mapper.DogMapper;
import com.jt.mapper.EmpMapper;
import com.jt.pojo.Dog;
import com.jt.pojo.Emp;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class TestMybatis4 {

    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private EmpMapper empMapper;

    //完成一对一测试
    @Test
    public void testEmp(){
        List<Emp> empList = empMapper.findAll();
        System.out.println(empList);
    }
}

3.2.6 编辑EmpMapper接口

@Mapper
public interface EmpMapper {
    List<Emp> findAll();
}

3.2.7 编辑EmpMapper.xml映射文件

 <!--
        知识点:
            1.如果单表查询首选resultType
            2.如果进行关联查询 首选resultMap
            3.如果sql的结果集出现了重名字段,则mybatis映射必然报错.
    -->
    <select id="findAll" resultMap="empRM">
        SELECT emp.*,dept.dept_name FROM emp,dept
        WHERE emp.dept_id = dept.dept_id
    </select>

    <!-- 完成一对一封装
        目的: 一个员工中封装一个部门对象
        语法:
            1.association 表示一对一封装
            2.property  当前主对象的属性名称
            3.javaType  指定属性的类型
    -->
    <resultMap id="empRM" type="Emp" autoMapping="true">
        <!-- 标识主键信息 -->
        <id column="emp_id" property="empId"/>
        <!--<result column="emp_name" property="empName"/>-->

        <!--完成一对一映射-->
        <association property="dept" javaType="Dept" autoMapping="true">
            <id column="dept_id" property="deptId"/>
        </association>
    </resultMap>

3.2.8 连接查询

SELECT emp.*,dept.dept_name FROM 
emp 
	LEFT JOIN
dept
	ON emp.dept_id = dept.dept_id

3.3 一对多查询

3.3.1 业务需求

需求: 一个部门对应多个员工
表现形式:
Mybatis_第8张图片

3.3.2 编辑测试代码

 @Test
    public void testDept(){
        List<Dept> deptList = deptMapper.findAll();
        System.out.println(deptList);
    }

3.3.3 编辑Mapper接口

@Mapper
public interface DeptMapper {
    List<Dept> findAll();
}

3.3.4 编辑DeptMapper.xml文件

<mapper namespace="com.jt.mapper.DeptMapper">

    <select id="findAll" resultMap="deptRM">
        SELECT dept.*,emp.emp_id,emp.emp_name
        FROM dept,emp
        WHERE dept.dept_id=emp.dept_id
    </select>
    <!--
        一对多封装:
            1.collection: 封装集合类型
            2.ofType:  指定集合内部(泛型)的对象类型
    -->
    <resultMap id="deptRM" type="Dept" autoMapping="true">
        <!--主键必须标识-->
        <id column="dept_id" property="deptId"/>
        <!--一对多封装-->
        <collection property="emps" ofType="Emp" autoMapping="true">
            <id column="emp_id" property="empId"/>
        </collection>
    </resultMap>

</mapper>

3.4 Mybatis的注解形式

	//鸡肋: 1.大公司一般不用,  2.只适用于单表操作.多表操作必须写映射文件
    // 注解和映射文件二选一
    @Select("select * from dept")
    List<Dept> selectAll();
    @Insert("insert into dept values (null,#{deptName})")
    void saveDept(Dept dept);

3.5 @MapperScan

Mybatis_第9张图片

4.1 Mybatis缓存实现

4.1.1 缓存机制

如果有大量相同的请求查询数据库,则数据库需要执行多次重复的sql,那么并发压力高,查询效率低. 如果引入缓存机制,则可以极大的提升用户的查询的效率
Mybatis_第10张图片

4.2 Mybatis-一级缓存

4.2.1 一级缓存说明

说明: 在同一个SqlSession内,实现数据库的共享.
解释: 用户使用同一个SqlSession时,进行多次数据库的查询,由于一级缓存的存在.所以数据库只查询一次.
开关状态: 一级缓存Mybatis默认开启.无需配置.

4.2.2 一级缓存测试说明

package com.jt;

import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@SpringBootTest
public class TestMybatisCache5 {

    @Autowired
    private UserMapper userMapper; //底层实现中包含了SqlSession

    /**
     * 测试:mybatis的一级缓存, SqlSession级别
     * SpringBoot测试说明:
     *   SpringBoot中用户在使用userMapper接口时,用户每调用一次.
     *   SpringBoot就会新创建一个SqlSession.
     * 如何解决多个SqlSession的问题?
     * 解决方案:
     *  利用@Transactional的事务的注解,将多个SqlSession控制为一个.
     */
    @Test
    @Transactional //事务的注解
    public void testCache1(){
        List<User> list1 = userMapper.findAll(); //sqlSession1
        List<User> list2 = userMapper.findAll(); //sqlSession2
        List<User> list3 = userMapper.findAll(); //SqlSession3
    }

}

4.3 Mybatis-二级缓存

4.3.1 二级缓存说明

说明: 由同一个SqlSessionFactory(类比:链接池)生产的SqlSession(类比:数据库链接),可以实现数据共享
解释说明: 由同一个SqlSessionFactory生产多个SqlSession(多线程).可以在多线程的条件下,可以实现数据共享.
默认开关: 二级缓存默认条件下是开启的. 但是需要指定哪里使用二级缓存

4.3.2 标识二级缓存

Mybatis_第11张图片

4.3.3 Mybatis二级缓存测试

 /**
     * 测试二级缓存
     * 总结: 多线程条件下共享数据,要求数据必须序列化.
     */
    @Test
    public void testCache2(){
        //第一次查询数据库获取的list1的集合对象,该对象需要保存到缓存中,为了后续线程使用,该对象必须序列化
        List<User> list1 = userMapper.findAll(); //sqlSession1  线程A
        //第二个线程查询数据.有二级缓存的存在.所以从缓存中获取数据.所以直接反序列化该对象获取结果.
        List<User> list2 = userMapper.findAll(); //sqlSession2  线程B
        //第三个线程查询数据,所以直接反序列化该对象获取结果.
        List<User> list3 = userMapper.findAll(); //SqlSession3  线程C
    }

4.3.4 关于对象序列化问题

说明: 在多线程条件下.数据如果需要共享,必须序列化
Mybatis_第12张图片

4.4 关于Mybatis一二级缓存的说明

  1. 默认条件下一二级缓存是开启的. 但是二级缓存需要标记 cache

Mybatis_第13张图片

  1. 一级缓存在同一个SqlSession中共享数据(单线程)
  2. 二级缓存在同一个SqlSessionFactory生产的多个SqlSession内共享数据(多线程). 对象必须序列化
  3. 在真实的生产环境中(集群:多个服务器)使用二级缓存可能存在问题,使用Redis高级缓存服务器代替.

4.5关于缓存的作用域问题

一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。 一级缓存的作用域是同一个SqlSession,在第一个sqlSession执行相同的sql语句后结果放在内存中,第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。
本地缓存不能被关闭,可以调用clearCache()来清空本地缓存,或者改变缓存的作用域

二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。
Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。
如果缓存中有数据就不用从数据库中获取,大大提高系统性能。

4.6 Mybatis底层实现原理(了解)

重点知识: 1.了解SqlSessionFactory/SqlSession如何创建的!!!

package com.jt;

import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class MybatisApplicationTests {
    /*
    * Mysql入门实现步骤:
    *   1.编辑mybatis-config.xml核心配置文件
    *       1.1执行数据源配置
    *   2.编辑POJO实体对象.要求与数据库表中的字段一一对应
    *   3.编辑Mapper接口. 添加接口方法
    *   4.编辑接口的实现类(配置文件方式) 要求namespace id  resultType
    *   5.mybatis加载指定的mapper映射文件
    *   6.创建SqlSessionFactory工厂对象
    *   7.获取SqlSession,开启数据库链接
    *   8.获取接口对象(代理对象)
    *   9.调用接口方法,获取返回值结果
    *   10.关闭sqlSession链接.
    * */
    @Test
    public void testDemo1() throws IOException {
        /*创建SqlSessionFactory 类比:链接池 */
        String resource = "mybatis/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //设计模式1:建造者模式-Builder-.build()
        //设计模式2:工厂模式-Factory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        /*从SqlSessionFactory中获取sqlSession*/
        SqlSession sqlSession = sqlSessionFactory.openSession();
        /*SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        SqlSession sqlSession3 = sqlSessionFactory.openSession();*/

        /*获取mapper接口,执行接口方法*/
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        /*Mybatis为接口创建了一个代理对象
            知识点: 框架中通过接口调用方法时,如果没有实现类,则为其创建代理对象
                    代理对象~实现类
         */
        System.out.println(userMapper.getClass());
        List<User> userList = userMapper.findAll();
        System.out.println(userList);

        /*执行之后关闭SqlSession*/
        sqlSession.close();
    }
}

数据自动回显

 useGeneratedKeys="true"  keyColumn="字段" keyProperty="属性名"

常用注解

  1. @Configuration 标识当前类是配置类
  2. @ComponentScan 包扫描注解 扫描注解 需要在配置类上面添加
  3. @Bean 标识该方法的返回值交给Spring容器管理 通常写在配置类中
    方法名类型首字母小写,返回值:需要被管理的对象"
  4. @Scope 控制多例和单例 通常与@bean一起使用
    @Scope(“singleton”) //标识单例对象
    @Scope(“prototype”) //标识多例对象
  5. @Lazy 懒加载 通常与@bean一起使用 来设置单例下的饿汉式与懒汉式
    注意:多例模式是懒加载,单例模式是饿汉式
  6. @PostConstruct 初始化方法 通常写在被Spring管理的对象里面
  7. @PreDestroy 销毁方法 通常写在被Spring管理的对象里面
  8. @Component 将当前类未来的对象交给容器管理 一般情况下用了此标签,就不需要在配置类里面配置@bean了
  9. @Autowired 按照类型进行注入
  10. @Qualifier 按照名称进行注入 通常跟@Autowired注解一起使用
  11. @Repository 标识持久层注解
  12. @Service 标识Service层
  13. @Controller 标识Controller层
  14. @Value 为属性赋值 @Value("${key}") 为对象中的属性赋值
  15. @PropertySource 加载指定路径的配置文件properties 标注在有@Value标签的类上
    @PropertySource(value = “classpath:/addUser.properties”,encoding = “UTF-8”)
    spring根据指定的路径,加载properties配置文件 数据添加到spring容器中
  16. @Aspect 标识当前类是一个切面类 注意切面类需要被 Spring管理
  17. @Pointcut 用于定义切入点表达式 表达式写法4种 如果方法上有此标签 我们把这个方法视为目标方法,也就是被代理的对象需要执行的业务逻辑方法
  18. @EnableAspectJAutoProxy 让AOP的注解有效果 添加到配置类上
  19. @Before AOP-前置通知
  20. @AfterReturning AOP-后置通知
  21. @AfterThrowing AOP-异常通知
  22. @After AOP-最终通知
  23. @Around AOP-环绕通知
  24. @Order(1) //可以利用order关键字 实现AOP的排序 数字越小越先执行. 意为:当一个方法需要执行多个AOP时,我们可以设置切面的执行顺序,此标签通常加在切面类上 如果遇到排序的数字一样,则还是按照文件夹的上下顺序执行
  25. @ResponseBody 将返回的数据转化为JSON串, 如果是字符串本身 原数据返回
  26. @RequestMapping("/hello") 实现浏览器的请求路径与方法的映射
  27. @PathVariable restFul结构,接收参数的注解.
  28. @GetMapping("") 只能接收GET请求类型
  29. @DeleteMapping("") 只能接收DELETE请求类型
  30. @PostMapping("") 只能接收POST请求类型
  31. @PutMapping("") 只能接收PUT请求类型
  32. @RestController 表示Controller类,同时要求返回值为JSON
  33. @CrossOrigin 允许跨域访问
  34. @RequestBody 参数接收时,将JSON串转化为java对象 json中的key与对象的属性一致.
  35. @Data lombok动态生成get/set/toString/equals/hashcode等方法
  36. @Accessors 控制是否开启链式加载结构
  37. @NoArgsConstructor 生成无参构造方法
  38. @AllArgsConstructor 生成全参构造方法
  39. @Mapper mybatis将当前的接口交给Spring容器管理. Map<类名小写,JDK动态代理对象>
  40. @SpringBootTest 该注解的作用在进行代码测试时启动spring容器,之后动态的获取对象 注意包路径 主启动类的同包及子包中.
  41. @Param Mybatis中将参数封装为Map集合.
    @Param(“maxAge”) int maxAge
  42. @Alias Mybatis中定义对象的别名 @Alias(“User”)
  43. @MapperScan Mybatis中扫描指定包路径的接口 为其创建代理对象.
  44. @Insert Mybatis 新增操作注解
  45. @Update Mybatis 修改操作注解
  46. @Delete Mybatis 删除操作注解
  47. @Select Mybatis 查询操作注解

你可能感兴趣的:(DataBases,java,intellij-idea,mybatis,spring,3,springmvc)