Mybatis详解

目录

  • 1.简介
    • 1.1 什么是Mybatis
    • 1.2 为什么需要Mybatis
  • 2、第一个Mybatis程序
    • 2.1 搭建环境
    • 2.2 创建一个模块
    • 2.3 编写代码
    • 2.4测试
  • 3、CRUD
    • 1、namespace
    • 2、select
    • 3、Insert
    • 4、update
    • 5、delete
    • 6、万能的Map
    • 7、模糊查询
  • 4、配置解析
    • 1、核心配置文件
    • 2、环境配置
    • 3、属性(properties)
    • 4、类型别名(typeAliases)
    • 5、设置
    • 6、其他配置
    • 7、映射器(mappers)
    • 8、作用域(Scope)和生命周期
  • 5、解决属性名和字段名不一致的问题:ResultMap
  • 6、日志
    • 6.1 日志工厂
    • 6.2 LOG4J
  • 7、分页
    • 7.1 使用limit分页
    • 7.2 RowBounds实现分页
    • 7.3 分页插件
  • 8、使用注解开发
    • 8.1 面向接口编程
    • 8.2使用注解开发
    • 8.3 CRUD
  • 9、Lombok
  • 10、多对一处理
    • 测试环境搭建
    • 按照查询嵌套处理
    • 按结果嵌套查询
  • 11、一对多处理
    • 1、搭建环境
    • 2.按结果嵌套查询
    • 3. 按查询嵌套处理
  • 12、动态SQL
    • 搭建环境
    • IF
    • choose when
    • set
    • Foreach
    • SQL片段
  • 13、缓存
    • 1. Mybatis缓存
    • 2、一级缓存
    • 3、二级缓存
    • 4、ehcache

1.简介

1.1 什么是Mybatis

https://mybatis.org/mybatis-3/zh/index.html

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

1.2 为什么需要Mybatis

帮助程序员将数据存入到数据库中

传统的jdbc代码太复杂。简化。框架。自动化。

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件。易于学习,易于使用。通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的orm字段关系映射。
  • 提供对象关系映射标签,支持对象关系组建维护。
  • 提供xml标签,支持编写动态sql。

2、第一个Mybatis程序

2.1 搭建环境

搭建数据库

新建普通maven项目,删src

导入依赖

<dependencies>
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>5.1.47version>
    dependency>
    
    <dependency>
        <groupId>org.mybatisgroupId>
        <artifactId>mybatisartifactId>
        <version>3.5.2version>
    dependency>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.13version>
        <scope>testscope>
    dependency>
dependencies>

2.2 创建一个模块

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。

1.resource文件下配置mybatis-config.xml


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            dataSource>
        environment>
    environments>
    <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
    mappers>
configuration>

2.编写工具类

//sqlSessionFactory----->sqlSession(类比preparedStatement)
public class MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory = null;
    static {
        try {
            //获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    
    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    // 你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
    public static SqlSession getsqlSession(){
        return sqlSessionFactory.openSession();
    }

}

2.3 编写代码

实体类

public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

Mapper接口(Dao)

List<User> getUserList();

Mapper.xml(Dao实现类)


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.cc.dao.UserDao">
    <select id="getUserList" resultType="com.cc.pojo.User">
        select * from mybatis.user
    select>
mapper>

在Mybatis-config.xml中注册Mapper:

<mappers>
    <mapper resource="com/cc/dao/UserMapper.xml"/>
mappers>

2.4测试

junit

配置文件无法被导出或生效:

<build>
    <resources>
        <resource>
            <directory>src/main/javadirectory>
            <includes>
                <include>**/*.xmlinclude>
                <include>**/*.propertiesinclude>
            includes>
        resource>

        <resource>
            <directory>src/main/resourcesdirectory>
            <includes>
                <include>**/*.xmlinclude>
                <include>**/*.propertiesinclude>
            includes>
        resource>
    resources>
build>

实体类中写toString方法,才能打印user

for (User user : userList) {
    System.out.println(user);
}

3、CRUD

1、namespace

<mapper namespace="com.cc.dao.UserMapper">

namespace中的包名要和Dao/mapper接口的包名一致

2、select

编写接口

User getUserById(int id);

编写实现

<select id="getUserById" parameterType="int" resultType="com.cc.pojo.User">
        select * from mybatis.user where id = #{id}
select>

id:就是对应的namespace中的方法名

resultType:Sql语句执行的返回值

parameterType:参数类型

编写测试

//增删改需要提交事务
@Test
public void addUser(){
    SqlSession sqlSession = MybatisUtil.getsqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    mapper.addUser(new User(4,"haha","123"));
    //提交事务
    sqlSession.commit();
    sqlSession.close();

}

3、Insert

<insert id="addUser" parameterType="com.cc.pojo.User">
    insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd})
insert>

4、update

<update id="updateUser" parameterType="com.cc.pojo.User">
    update mybatis.user
    set name = #{name},pwd = #{pwd}
    where id = #{id};
update>

5、delete

<delete id="deleteUser" parameterType="int">
    delete
    from mybatis.user
    where id = #{id};
delete>

6、万能的Map


<insert id="addUser2" parameterType="map">
    insert into mybatis.user(id,pwd) values (#{userid},#{password})
insert>
@Test
public void addUser2(){
    SqlSession sqlSession = MybatisUtil.getsqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map map = new HashMap<>();
    map.put("userid",5);
    map.put("password","222233");
    mapper.addUser2(map);
    //提交事务
    sqlSession.commit();
    sqlSession.close();

}

Mybatis详解_第1张图片

7、模糊查询

<select id="getUserLike" resultType="com.cc.pojo.User">
    select * from user where name like "%"#{value}"%"
select>
@Test
public void getUserLike(){
    SqlSession sqlSession = MybatisUtil.getsqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userLike = mapper.getUserLike("李");
    for (User user : userLike) {
        System.out.println(user);
    }
    sqlSession.commit();
    sqlSession.close();
}

或#{value} “%李%”

4、配置解析

1、核心配置文件

mybatis-config.xml

configuration(配置):
    properties(属性)
    settings(设置)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境配置)
    environment(环境变量):
        transactionManager(事务管理器)
        dataSource(数据源)
    databaseIdProvider(数据库厂商标识)
    mappers(映射器)

2、环境配置

Mybatis详解_第2张图片

3、属性(properties)

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。

driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8username=truepassword=123456

在核心配置文件中引入(注意顺序)


<properties resource="db.properties"/>

image-20220128202159094

4、类型别名(typeAliases)

1、类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

<typeAliases>
    <typeAlias type="com.cc.pojo.User" alias="User"/>
typeAliases>
<select id="getUserList" resultType="User">

2、或者指定实体类的包,mybatis会在包下搜索需要的JavaBean。类名首字母小写。

<typeAliases>
    <package name="com.cc.pojo"/>
typeAliases>
<select id="getUserList" resultType="user">

实体类较少,使用第一种,实体类多,使用第二种

第一种可以diy别名

3、每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:

@Alias("author")
public class Author {
    ...
}

5、设置

Mybatis详解_第3张图片

image-20220128205758747

6、其他配置

Mybatis详解_第4张图片

7、映射器(mappers)

方式一:

<mappers>
    <mapper resource="com/cc/mapper/UserMapper.xml"/>
mappers>

方式二:使用class文件绑定注册

<mappers>    <mapper class="com.cc.mapper.UserMapper"/>mappers>

注意点:接口和它的Mapper配置文件必须同名且在同一个包下

方式三:使用扫描包进行注入绑定

<mappers>    <package name="com.cc.mapper"/>mappers>

注意点:接口和它的Mapper配置文件必须同名且在同一个包下

8、作用域(Scope)和生命周期

不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder

  • 一旦创建了 SqlSessionFactory,就不再需要它了。
  • 局部变量

SqlSessionFactory

  • 可以类比数据库连接池
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在
  • SqlSessionFactory 的最佳作用域是应用作用域(全局)。
  • 最简单的就是使用单例模式或者静态单例模式。

SqlSession

  • 每个线程都应该有它自己的 SqlSession 实例。(连接到池的一个请求)
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 用完赶紧关闭,否则资源被占用

Mybatis详解_第5张图片

每个Mapper代表一个具体业务

5、解决属性名和字段名不一致的问题:ResultMap

数据库中的字段:

Mybatis详解_第6张图片

测试实体类字段不一致的情况:

private int id;private String name;private String password;
select * from mybatis.user where id = #{id}即 select id,name,pwd from mybatis.user where id = #{id}
Mybatis详解_第7张图片

解决办法:

  • 起别名
select id,name,pwd as password from mybatis.user where id = #{id}
  • resultMap

结果集映射(显式)

<resultMap id="UserMap" type="User">        <result column="pwd" property="password"/>resultMap><select id="getUserById" resultMap="UserMap">    select * from mybatis.user where id = #{id}select>
  • resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。

  • 之前你已经见过简单映射语句的示例,它们没有显式指定 resultMap。比如:

    <select id="selectUsers" resultType="map">
    

上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。虽然在大部分情况下都够用,但是 HashMap 并不是一个很好的领域模型。

  • MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。
<select id="selectUsers" resultType="User">  select    user_id             as "id",    user_name           as "userName",    hashed_password     as "hashedPassword"  from some_table  where id = #{id}select>

6、日志

6.1 日志工厂

曾经:sout debug

现在:日志工厂

Mybatis详解_第8张图片

  • SLF4J
  • LOG4J(deprecated since 3.5.9) 【掌握】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING 【掌握】
  • NO_LOGGING

在Mybatis具体使用哪一个日志实现,在设置中设定

<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
settings>

6.2 LOG4J

Mybatis详解_第9张图片

1.先导入LOG4J的包


<dependency>
    <groupId>log4jgroupId>
    <artifactId>log4jartifactId>
    <version>1.2.17version>
dependency>

2.写配置文件log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

3.配置log4j为日志的实现

<settings>
    <setting name="logImpl" value="LOG4J"/>
settings>

4.LOG4J的使用

Mybatis详解_第10张图片

7、分页

7.1 使用limit分页

Mybatis详解_第11张图片

List<User> getUserByLimit(Map<String,Integer> map);
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">    select * from user limit #{startIndex},#{pageSize}select>
@Test
    public void getUserByLimit(){
        SqlSession sqlSession = MybatisUtil.getsqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String, Integer> map = new HashMap<String,Integer>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> userByLimit = mapper.getUserByLimit(map);
        for (User user : userByLimit) {
            System.out.println(user);
        }
        sqlSession.close();
    }

7.2 RowBounds实现分页

List<User> getUserByRowBounds();
<select id="getUserByLimit" resultMap="UserMap">
    select * from user
select>
@Test
public void getUserByRowBounds(){
    SqlSession sqlSession = MybatisUtil.getsqlSession();
    //RowBounds实现
    RowBounds rowBounds = new RowBounds(1,2);
    //通过java代码层面实现分页
    List<User> userList = sqlSession.selectList("com.cc.mapper.UserMapper.getUserByRowBounds",null,rowBounds);
    for (User user : userList) {
        System.out.println(user);
    }
    sqlSession.close();
}

7.3 分页插件

Mybatis详解_第12张图片

8、使用注解开发

8.1 面向接口编程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WZlXtBJ0-1643705679030)(https://gitee.com/roadside-stall/images/raw/master/imgs/20220130192709.png)]

Mybatis详解_第13张图片

8.2使用注解开发

1、注解在接口上实现

@Select("select * from user")List<User> getUsers();

2、需要再核心配置文件中绑定接口

<mappers>    <mapper class="com.cc.mapper.UserMapper"/>mappers>

3、测试

@Testpublic void getUsers(){    SqlSession sqlSession = MybatisUtil.getsqlSession();    //底层主要应用反射    UserMapper mapper = sqlSession.getMapper(UserMapper.class);    List users = mapper.getUsers();    for (User user : users) {        System.out.println(user);    }    sqlSession.close();}

本质:反射机制实现

底层:动态代理

Mybatis详细的执行流程!

Mybatis详解_第14张图片

8.3 CRUD

可以在工具类创建的时候实现自动提交事务

public static SqlSession getsqlSession(){
    return sqlSessionFactory.openSession(true);
}

Mybatis详解_第15张图片

Mybatis详解_第16张图片

9、Lombok

使用步骤:

1、在IDEA中安装Lombok插件

2、导入Lombok的jar包


<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <version>1.18.22version>
dependency>

3、在实体类上加注解即可

@Data:无参构造,getter,setter,tostring,hashcode,equals

@AllArgsConstructor有参

@NoArgsConstructor无参

@Getter and @Setter
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder

10、多对一处理

一个老师---->多个学生

测试环境搭建

1、导入Lombok

2、新建实体类Teacher Student

3、建立Mapper接口

4、建立Mapper.xml文件

5、在核心配置文件中绑定注册Mapper

6、测试查询

按照查询嵌套处理

第一种:select id,name,tid from student where tid=(select id from teacher)

<select id="getStudent" resultMap="StudentTeacher">
    select * from student
select>

<resultMap id="StudentTeacher" type="Student">
    
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
resultMap>

<select id="getTeacher" resultType="Teacher">
    select * from teacher where id = #{tid}
select>

按结果嵌套查询

第二种:select s.id,s.name,t.name from student s,teacher t where s.tid=t.id


<select id="getStudent2" resultMap="StudentTeacher2">
    select s.id sid,s.name sname,t.name tname
    from student s,teacher t
    where s.tid=t.id
select>
<resultMap id="StudentTeacher2" type="Student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="Teacher">
        <result property="name" column="tname"/>
    association>
resultMap>

11、一对多处理

1、搭建环境

实体类

@Data
public class Student {
    private int id;
    private String name;
    //学生关联一个老师
    private int tid;
}
@Datapublic class Teacher {    private int id;    private String name;    //一个老师拥有多个学生    private List students;}

2.按结果嵌套查询


<select id="getTeacher" resultMap="TeacherStudent">
    select s.id sid,s.name sname,t.name tname,t.id tid
    from teacher t,student s
    where s.tid = t.id and t.id = #{tid}
select>
<resultMap id="TeacherStudent" type="Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    
    <collection property="students" ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    collection>
resultMap>

3. 按查询嵌套处理


<select id="getTeacher2" resultMap="TeacherStudent2">
    select * from teacher where id = #{tid}
select>
<resultMap id="TeacherStudent2" type="Teacher">
    <collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId"/>
resultMap>
<select id="getStudentByTeacherId" resultType="Student">
    select * from student where tid = #{id}
select>

小结

1.关联-association 多对一

2.集合-collection 一对多

3.JavaType & ofType

javaType:用来指定实体类中属性的类型

ofType:用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

12、动态SQL

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

搭建环境

CREATE TABLE `blog`(
  `id` VARCHAR(50) NOT NULL COMMENT '博客id',
  `title` VARCHAR(100) NOT NULL COMMENT '博客标题',
  `author` VARCHAR(30) NOT NULL COMMENT '博客作者',
  `create_time` DATETIME NOT NULL COMMENT '创建时间',
  `views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8
//实体类
@Data
public class Blog {
    private int id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

IF

List<Blog> queryBlogIF(Map map);
<select id="queryBlogIF" parameterType="map" resultType="blog">
    select * from blog where 1=1
    <if test="title != null">
        and title = #{title}
    if>
    <if test="author != null">
        and author = #{author}
    if>
select>
@Testpublic void queryBlogIF(){    SqlSession sqlSession = MybatisUtil.getsqlSession();    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);    HashMap hashMap = new HashMap();    hashMap.put("title","Java");    hashMap.put("author","狂神说");    List<Blog> blogs = mapper.queryBlogIF(hashMap);    for (Blog blog : blogs) {        System.out.println(blog);    }    sqlSession.close();}

choose when

<select id="queryBlogChoose" parameterType="map" resultType="blog">    select * from blog    <where>        <choose>            <when test="title != null">                title = #{title}            when>            <when test="author != null">                and author = #{author}            when>            <otherwise>                and views = #{views}            otherwise>        choose>    where>select>

set

<update id="updateBlog" parameterType="map">
    update blog
    <set>
        <if test="title!=null">
            title = #{title},
        if>
        <if test="author!=null">
            author = #{author},
        if>
    set>
        where id = #{id}
update>

Foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。

List<Blog> queryBlogForeach(Map map);
eg. select * from blog where 1=1 and (id=1 or id=2 or id=3)
<select id="queryBlogForeach" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
            id = #{id}
        foreach>
    where>
select>
@Test
public void queryBlogForeach(){
    SqlSession sqlSession = MybatisUtil.getsqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    ArrayList<Integer> ids = new ArrayList<>();
    ids.add(1);
    map.put("ids",ids);
    List<Blog> blogs = mapper.queryBlogForeach(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

SQL片段

<sql id="if-title-author">
    <if test="title!=null">
        title = #{title},
    if>
    <if test="author!=null">
        author = #{author},
    if>
sql>
<update id="updateBlog" parameterType="map">
    update blog
    <set>
        <include refid="if-title-author">include>
    set>
        where id = #{id}
update>

Mybatis详解_第17张图片

动态SQL就是在拼接SQL语句

建议:

  • 先在MySQL中写出完整SQL,再去对应修改为动态SQL实现通用即可

Mybatis详解_第18张图片

13、缓存

1. Mybatis缓存

Mybatis详解_第19张图片

Mybatis详解_第20张图片

2、一级缓存

image-20220201144554924

测试步骤:

1.开启日志

2.测试在一个session中查询两次相同记录

3.查看日志输出

Mybatis详解_第21张图片

缓存失效情况:

1.查询不同东西

2.增删改操作,可能会改变原来的数据,所以必定刷新缓存

Mybatis详解_第22张图片

3.查询不同的Mapper.xml

4.手动清理缓存

sqlSession.clearCache();//手动清理

小结:一级缓存默认开启,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段

3、二级缓存

Mybatis详解_第23张图片

要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

可用的清除策略有:

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

默认的清除策略是 LRU。

步骤:

1.开启全局缓存


<setting name="cacheEnable" value="true"/>

2.在要使用二级缓存中的Mapper中开启

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

3.测试

​ 问题:只写标签,需要将实体类序列化!

​ readOnly默认为false,只读不报错,可读写的缓存会通过序列化返回缓存对象的拷贝,此时需要实体类实现Serializable接口或配置 readOnly=“true”

小结

只要开启了二级缓存,在同一个Mapper下就有效

所有的数据都会先放在一级缓存中

只有当会话提交或关闭的时候,才会提交到二级缓存中

查找顺序:先看二级缓存中有没有,再看一级缓存中有没有,再查询数据库

4、ehcache

ehcache是一种广泛使用的开源Java分布式操作,主要面向通用缓存

1.导包


<dependency>
    <groupId>org.mybatis.cachesgroupId>
    <artifactId>mybatis-ehcacheartifactId>
    <version>1.2.1version>
dependency>

2.在mapper中指定使用ehcache缓存实现

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

3.配置文件ehcache.xml


<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <diskStore path="./tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
ehcache>

你可能感兴趣的:(java,mybatis)