0


快速掌握 MyBatis 框架(二)

文章目录

一、前言

快速掌握 MyBatis 框架(一)

1.1 数据库与表

createdatabaseifnotexists library;use library;droptableifexists book;createtable book(
    id intprimarykeyauto_increment,-- 书籍Id
    bookName varchar(100)notnull,-- 书名
    content varchar(1024)notnull,-- 书籍内容
    authorId intnotnull,-- 作者Id`state`intdefault1-- 借出状态,默认为1,未借出);droptableifexists author;createtable author(
    id intprimarykeyauto_increment,-- 作者Id
    authorName varchar(100)notnull,-- 作者名字
    age int,-- 作者年龄
    nationality varchar(250)-- 作者国籍);

1.2 实体类

//书籍类@DatapublicclassBook{privateInteger id;privateString bookName;privateString content;privateInteger authorId;privateInteger state;privateAuthor author;}
//作者类@DatapublicclassAuthor{privateInteger id;privateString authorName;privateInteger age;privateString nationality;privateList<Book> books;}

1.3 MyBatisX 插件

在写 MyBatis 代码的时候有一个非常好用的插件——

MyBatisX

选择 File->Settings ,然后进行如下操作进行插件的安装

在这里插入图片描述

该插件可以实现接口代码和对应的 XML 文件中的代码的跳转

在这里插入图片描述

而且写好一个 接口方法后可以在对应的 XML 文件中自动生成代码(出现红下划线,Alt+Enter,选择第一个选项),当然,这样的方式生成的标签不一定是我们想要的

在这里插入图片描述
在这里插入图片描述

1.4 SQL 日志查看配置

为了查看写好的 SQL ,可以在配置文件中进行配置,如此,在控制台就可以查看 SQL 日志

mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

二、多表查询

在前面一篇文章中有讲数据库的增加(insert)、删除(delete)、修改(update)、查询(select)操作

增删改

这三个操作

返回的值都是影响的行数

,所以在写 SQL 的 XML 时并不需要指定返回类型,但是如果是

查询操作

就需要

通过 resultType 来设置返回类型

,就算是 String 类型,返回值也要设置为 resultType =“java.lang.String”

但是如果进行

多表查询

,实体类中就会有一个属性为另一个实体类,比如上面的实体类定义中,一本书对应一个作者,想要将作者的完整信息都放在书籍类中。一个作者可以写很多本书,想要将这个作者写的所有书的信息都放在一个 List 中。这样的情况,简简单单通过 resultType 已经没有办法实现,如果只是使用 resultType ,会发现对应的类的属性值为 null(变量 author 和 变量 books 的值为 null)

此时就需要使用

resultMap

,返回一个字典映射

2.1 一对一

一本书对应一个作者的情况

interface

@MapperpublicinterfaceBookMapper{publicBookgetBookById(Integer id);}

XML

BookMapper.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.example.demo.Mapper.BookMapper"><resultMapid="BaseMap"type="com.example.demo.model.Book"><idproperty="id"column="id"></id><resultproperty="bookName"column="bookName"></result><resultproperty="content"column="content"></result><resultproperty="authorId"column="authorId"></result><resultproperty="state"column="state"></result><associationproperty="author"resultMap="com.example.demo.Mapper.AuthorMapper.BaseMap"columnPrefix="a_"></association></resultMap><selectid="getBookById"resultMap="BaseMap">
        select b.*,a.id a_id,a.authorName a_authorName,a.age a_age,a.nationality a_nationality
        from book b left join author a
        on b.authorId = a.id where b.id = #{id}
    </select></mapper>

解释:

  1. select 标签中的 resultMap 的值 “BaseMap” 就是一个标识和上面 resultMap 标签中的 id 属性值 “BaseMap” 是对应的,起什么名字都行,
  2. resultMap 标签中的 type 属性值为映射的实体类的包名加类名
  3. id 标签指的是主键result 标签指的是普通列
  4. property 属性指的是程序中的属性名,column 属性指的是数据库中的字段名。因此,即使程序中的属性名和数据库中的字段名不一致也不要紧,通过这样的映射就不会出错
  5. 由于是一对一的多表查询,使用的是association标签。 - property属性指的是 Book 类中关联的 Author 类的变量,即 author;- resultMap 属性指的是指定关联的结果集映射,将基于该映射配置来组织用户数据,这里关联的就是 AuthorMapper 里的 BaseMap(就是下面的代码);- columnPrefix 属性指的是给关联的数据库中的 column 添加一个前缀(如果不添加前缀,当 author 表和 book 表中同时有 id 字段,查询结果时一定会产生覆盖,使得两个 id 的值一样);

AuthorMapper.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.example.demo.Mapper.AuthorMapper"><resultMapid="BaseMap"type="com.example.demo.model.Author"><idproperty="id"column="id"></id><resultproperty="authorName"column="authorName"></result><resultproperty="age"column="age"></result><resultproperty="nationality"column="nationality"></result></resultMap></mapper>

单元测试代码

@SpringBootTestclassBookMapperTest{@AutowiredprivateBookMapper mapper;@TestvoidgetBookById(){System.out.println(mapper.getBookById(1));}}

结果显示

在这里插入图片描述

2.2 一对多

一对多和一对一的写法大体上是一样的额,不同的是一对一使用的是 association 标签,一对多使用的是

collection

标签

interface

publicList<Author>getAuthor(Integer id);

XML

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.example.demo.Mapper.AuthorMapper"><resultMapid="BaseMap"type="com.example.demo.model.Author"><idproperty="id"column="id"></id><resultproperty="authorName"column="authorName"></result><resultproperty="age"column="age"></result><resultproperty="nationality"column="nationality"></result><collectionproperty="books"resultMap="com.example.demo.Mapper.BookMapper.BaseMap"columnPrefix="b_"></collection></resultMap><selectid="getAuthor"resultMap="BaseMap">
        select a.*,b.id b_id,b.bookName b_bookName,b.content b_content
        from author a left join book b
        on a.id = b.authorId where a.id = #{id}
    </select></mapper>

关联的BookMapper 中的 BaseMap 在上面一对一的代码中已经写了

单元测试代码

@TestvoidgetAuthor(){List<Author> list = mapper.getAuthor(1);
    list.stream().forEach(n->System.out.println(n));}

结果展示

在这里插入图片描述

三、动态 SQL 使用

为了应对各种各样的需求,就需要动态 SQL 完成不同条件下不同的 SQL 拼接

3.1 < if > 标签

在完善信息的时候,有些信息是必须要填的,有些是非必填的。就像 author 表中作者的信息一样,只有 authorName 是一定要填写的,age 和 nationality 是非必填的,那么在插入数据的时候,就需要应对各种信息插入情况,就需要用 < if > 标签来判断传来的值是否为 null,如果是就不将内容拼接到 SQL 中

interface

publicintsetAuthor3(Author author);

XML

<insertid="setAuthor3">
    insert into author(authorName
    <iftest="age != null">
        ,age
    </if><iftest="nationality != null">
        ,nationality
    </if>
    ) values(#{authorName}
    <iftest="age != null">
        ,#{age}
    </if><iftest="nationality != null">
        ,#{nationality}
    </if>
    )
</insert>

解释:

  1. 通过 if 标签中的 test属性中的内容(对象中的属性)是否为空来决定是否将其拼接到 SQL 语句中
  2. 需要注意拼接时的逗号以及括号,保证在任何情况下都能组装成正确的 SQL 语句
  3. 由于需要判空,因此创建实体类的时候最好使用包装类,比如使用 Integer 类型而不是 int 类型。因为 int 类型默认值为 0 ,不会为 null,而 0 和 null 还是有很大区别的,使用 int 类型会存在报错的风险

测试代码展示

@TestvoidsetAuthor3(){Author author =newAuthor();
    author.setAuthorName("钱七");
    author.setNationality("马来西亚");System.out.println("更新的数据条数:"+mapper.setAuthor3(author));}

结果显示

在这里插入图片描述

3.2 < trim > 标签

该标签是配合 if 标签进行使用,试想极端情况,所有的参数都是非必传的,那么在不知道哪个参数是第一个,哪个参数是最后一个的情况下,一定会有多出来的逗号,trim 标签就可以解决这样的问题

trim 标签的属性

  • prefix:表示整个语句块以 prefix 的值作为前缀
  • suffix:表示整个语句块以 suffix 的值作为后缀
  • prefixOverrides:表示整个语句块要去除的前缀
  • suffixOverrides:表示整个语句块要去除的后缀

interface

publicintsetAuthor4(Author author);

XML

<insertid="setAuthor4">
    insert into author
    <trimprefix="("suffix=")"prefixOverrides=","><iftest="authorName != null">
            ,authorName
        </if><iftest="age != null">
            ,age
        </if><iftest="nationality != null">
            ,nationality
        </if></trim>
    values
    <trimprefix="("suffix=")"suffixOverrides=","><iftest="authorName != null">
            #{authorName},
        </if><iftest="age != null">
            #{age},
        </if><iftest="nationality != null">
            #{nationality},
        </if></trim></insert>

注意:如果

trim 标签中的内容没有一条条件成立 ,就不会执行 trim 语句的内容了,包括其属性也不会生效

。因此如果有必传参数,就往 trim 标签中添加必传参数;如果没有任何必传参数,前缀后缀相关属性就在 trim 中设置

单元测试代码

@TestvoidsetAuthor4(){Author author =newAuthor();
    author.setAuthorName("朱八");
    author.setAge(66);System.out.println("更新的数据条数:"+mapper.setAuthor4(author));}

结果显示

在这里插入图片描述

3.3 < where > 标签

传入一个对象,根据属性进行 where 条件查询,只要对象中的属性不为 null 就是查询条件

interface

publicList<Book>getBookByIdOrAuthorId(Book book);

XML

<selectid="getBookByIdOrAuthorId"resultType="com.example.demo.model.Book">
    select * from book
    <where><iftest="id != null">
            id=#{id}
        </if><iftest="authorId != null">
            and authorId=#{authorId}
        </if></where></select>

解释:

  1. where 标签自带 where 关键字,并且会自动去除多余的 and
  2. 可以使用 < trim prefix=“where” prefixOverrides=“and” > 替换

单元测试代码

@TestvoidgetBookByIdOrAuthorId(){Book book =newBook();
    book.setAuthorId(1);List<Book> list = mapper.getBookByIdOrAuthorId(book);
    list.stream().forEach(n->System.out.println(n));}

结果显示

在这里插入图片描述

3.4 < set > 标签

传入一个对象,根据属性进行更新用户的数据,比如根据传入的对象的 id ,修改其他不为 null 的属性

interface

publicintupdateBook(Book book);

XML

<updateid="updateBook">
    update book 
    <set><iftest="bookName != null">
            bookName=#{bookName},
        </if><iftest="content != null">
            content=#{content},
        </if><iftest="authorId != null">
            authorId=#{authorId}
        </if></set>
    where id=#{id}
</update>

解释:

  1. set 标签自带 set 关键字,会自动去除多余的逗号
  2. 可以使用 < trim prefix=“set” suffixOverrides=“,”> 替换

单元测试代码

@TestvoidupdateBook(){Book book =newBook();
    book.setId(1);
    book.setContent("更新内容~");System.out.println("更新数据的条数:"+mapper.updateBook(book));}

结果显示

在这里插入图片描述

3.5 < foreach > 标签

需要对一个集合遍历时使用该标签

foreach 标签属性

  • collection:绑定方法参数中的集合(List、Set、Map、数组…)
  • item:用于指定遍历时的每一个对象
  • open:整个语句块开头的字符串
  • close:整个语句块结束的字符串
  • separator:遍历元素之间间隔的字符串

interface

publicintdeleteByIdList(List<Integer> list);

XML

<deleteid="deleteByIdList">
    delete from book where id in
    <foreachcollection="list"item="bookId"open="("close=")"separator=",">
        #{bookId}
    </foreach></delete>

单元测试代码

@TestvoiddeleteByIdList(){List<Integer> list =newArrayList<>();
    list.add(1);
    list.add(3);System.out.println("更新数据的条数:"+mapper.deleteByIdList(list));}

结果显示

在这里插入图片描述

完~~~

标签: mybatis java mysql

本文转载自: https://blog.csdn.net/weixin_46103589/article/details/125499725
版权归原作者 富春山居_ZYY 所有, 如有侵权,请联系我们删除。

“快速掌握 MyBatis 框架(二)”的评论:

还没有评论