• mybatis小记


    mybatis java的持久化框架,和直接使用JDBC的区别是:
    使用JDBC需要在代码中写sql语句,返回类型等只能通过JDBC方法来确定,耦合程度高。
    mabatis通过约定的mapper接口和config xml来将sql的配置和使用隔离开,清晰的返回类型,方便的连接数据库等等。
    本文将就mybatis常用的功能说,更多的关于mybatis的配置请查阅官网

    一、mybatis基础配置和增删改查

    1.mybatis配置:

    resource文件夹下新建mybatis-config.xml,主要是配置在各种环境下通过什么策略来连接数据库(比如dev环境和生产环境的数据库是不同的),以及Mapper类的相应config信息

    
    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.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
                    <property name="username" value="****"/>
                    <property name="password" value="****"/>
                dataSource>
            environment>
        environments>
        <mappers>
            <mapper resource="dao/UserMapper.xml"/>
        mappers>
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.可使用properties字段来创建属性值

    <properties resource="org/mybatis/example/config.properties">
      <property name="username" value="dev_user"/>
      <property name="password" value="F2Fa3!33TYyg"/>
    properties>
    
    • 1
    • 2
    • 3
    • 4

    配置好了properties后,在xml的配置文件中可以使用${}来获取相应的属性,也是将配置和使用隔离开的模式
    例如

    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    dataSource>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.创建mybatisUtil工具类来创建Java mybatis数据库连接,主要是获取mybatis config

    package utils;
    
    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 java.io.IOException;
    import java.io.InputStream;
    
    public class MybatisUtil {
        private static SqlSessionFactory sqlSessionFactory;
        static {
            try {
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
        public static SqlSession openSqlSession() {
            return sqlSessionFactory.openSession();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    4.创建dao/UserMapper.java接口以规范Mapper类的行为

    package dao;
    
    import java.util.List;
    
    public interface UserMapper {
        List<User> getUsers();
        User getUserByName(String name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.通过创建dao/UserMapper.xml来配置Mapper的行为,主要是Mapper类约定的接口信息,相应的方法和返回类型是什么,相应的sql是什么

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="dao.UserMapper">
        <select id="getUsers" resultType="dao.User">
            select * from mybatis.User
        select>
        <select id="getUserByName" resultType="dao.User">
            select * from mybatis.User where name = #{name}
        select>
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    6.App中调用mybatis的函数来获取Mapper并调用相应的方法

    SqlSession sqlSession = MybatisUtil.openSqlSession();
            try {
                UserMapper mapper = sqlSession.getMapper(UserMapper.class);
                User users = mapper.getUserByName("A");
                System.out.println(users);
    //            users.stream().forEach(System.out::println);
            }
            finally {
                sqlSession.close();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可以看出mybatis在简单的增删改查中主要就是配置,首先配置怎么连接数据库,然后读取数据库配置并返回相应Java 连接对象,再通过配置好的Mapper调用相应的方法就可以实现和数据库的交互,整体上实现了配置和使用的分离。mybatis的配置只要一次,Mapper的配置是简单的,多一个sql语句就多一行的配置

    7.类型别名

    为java类型创建别名以简化xml配置的书写

    <typeAliases>
      <typeAlias alias="Author" type="domain.blog.Author"/>
      <typeAlias alias="Blog" type="domain.blog.Blog"/>
      <typeAlias alias="Comment" type="domain.blog.Comment"/>
      <typeAlias alias="Post" type="domain.blog.Post"/>
      <typeAlias alias="Section" type="domain.blog.Section"/>
      <typeAlias alias="Tag" type="domain.blog.Tag"/>
    typeAliases>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Mapper的另外用法

    
    <mappers>
      <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
      <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
      <mapper resource="org/mybatis/builder/PostMapper.xml"/>
    mappers>
    
    <mappers>
      <mapper url="file:///var/mappers/AuthorMapper.xml"/>
      <mapper url="file:///var/mappers/BlogMapper.xml"/>
      <mapper url="file:///var/mappers/PostMapper.xml"/>
    mappers>
    
    <mappers>
      <mapper class="org.mybatis.builder.AuthorMapper"/>
      <mapper class="org.mybatis.builder.BlogMapper"/>
      <mapper class="org.mybatis.builder.PostMapper"/>
    mappers>
    
    <mappers>
      <package name="org.mybatis.builder"/>
    mappers>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    二、mybatis对java对象和数据库表的映射

    使用一个持久层框架时,很关键的一点就是为了实现数据库到内存对象的映射(否则为什么不直接print出来呢),mybatis能够流行的重要原因就是其内置的表项的映射非常友好
    mybatis支持如下的映射方式:

    1.resultMap映射

    把resultMap放在前面是因为复杂的映射仍然需要用resultMap实现,而简单的映射已经可以使用mybatis3中的java注解来实现
    resultMap功能强大,可以将非常复杂的表正确的映射到内存对象中
    resultMap中存在以下关键字段:

    constructor - 用于在实例化类时,注入结果到构造方法中
    	idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
    	arg - 将被注入到构造方法的一个普通结果
    id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
    result – 注入到字段或 JavaBean 属性的普通结果
    association – 一个复杂类型的关联;许多结果将包装成这种类型
    嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
    collection – 一个复杂类型的集合
    嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
    discriminator – 使用结果值来决定使用哪个 resultMap
    	case – 基于某些值的结果映射
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其中constructor, id, result都是非常简单的字段
    其通用的匹配方式如下

    <result,id,idArg,arg property="*" column="*">
    
    • 1

    其中property表明了其在java对象中的字段名,column表示其在表中的字段名
    association表明了一个复杂的类型,通常需要进行更进一步的拆分,例如如下的询问

    <select id="selectBlog" resultMap="blogResult">
      select
        B.id            as blog_id,
        B.title         as blog_title,
        A.id            as author_id,
        A.username      as author_username,
        A.password      as author_password,
        A.email         as author_email,
        A.bio           as author_bio,
        CA.id           as co_author_id,
        CA.username     as co_author_username,
        CA.password     as co_author_password,
        CA.email        as co_author_email,
        CA.bio          as co_author_bio
      from Blog B
      left outer join Author A on B.author_id = A.id
      left outer join Author CA on B.co_author_id = CA.id
      where B.id = #{id}
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Author的字段如下

    <resultMap id="authorResult" type="Author">
      <id property="id" column="author_id"/>
      <result property="username" column="author_username"/>
      <result property="password" column="author_password"/>
      <result property="email" column="author_email"/>
      <result property="bio" column="author_bio"/>
    resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此时resultMap就应该如下,其中association就需要用若干个字段组装起来

    <resultMap id="blogResult" type="Blog">
      <id property="id" column="blog_id" />
      <result property="title" column="blog_title"/>
      <association property="author"
        resultMap="authorResult" />
      <association property="coAuthor"
        resultMap="authorResult"
        columnPrefix="co_" />
    resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果觉得resultMap重新列出来非常麻烦,可以使用如下语法,可以不用列出resultMap

    <association property="author">
    	<id property="id" column="author_id"/>
     	<result property="username" column="author_username"/>
      	<result property="password" column="author_password"/>
      	<result property="email" column="author_email"/>
      	<result property="bio" column="author_bio"/>
    association>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    难以想象这种东西在JDBC里面要写多少行,为了将映射关系隔离出来,你可能会需要创建一些工具类以避免代码的耦合,在这些工具类中还需要进行仔细的字段传递,而mybatis很好的解决了这些问题

    2.resultMap中的鉴别器(case)

    一个鉴别器可以如下

    <resultMap id="vehicleResult" type="Vehicle">
      <id property="id" column="id" />
      <result property="vin" column="vin"/>
      <result property="year" column="year"/>
      <result property="make" column="make"/>
      <result property="model" column="model"/>
      <result property="color" column="color"/>
      <discriminator javaType="int" column="vehicle_type">
        <case value="1" resultMap="carResult"/>
        <case value="2" resultMap="truckResult"/>
        <case value="3" resultMap="vanResult"/>
        <case value="4" resultMap="suvResult"/>
      discriminator>
    resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    鉴别器的作用类似于switch case,可以将表项根据某些字段的结果进行不同对象的封装

    3.resultType以及自动映射

    mybatis的自动映射将获取到的表和java对象字段进行忽略大小写的,忽略驼峰和蛇形命名法的匹配。有三种自动映射等级:
    NONE:禁用自动映射
    PARTIAL:对除了连接的属性进行映射
    FULL:全自动映射
    默认值为PARTIAL,PARTIAL和FULL的区别如下:

    <select id="selectBlog" resultMap="blogResult">
      select
        B.id,
        B.title,
        A.username,
      from Blog B left outer join Author A on B.author_id = A.id
      where B.id = #{id}
    select>
    
    <resultMap id="blogResult" type="Blog">
      <association property="author" resultMap="authorResult"/>
    resultMap>
    
    <resultMap id="authorResult" type="Author">
      <result property="username" column="author_username"/>
    resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    由于表中存在id字段,而Auther对象中也存在id字段,因此这两者进行了自动映射,而这显然是不符合我们预期的,因此一般来说用PARTIAL即可

    而resultType映射就相当于只是指定了一个java对象并让mybatis进行自动映射

    4.java注解映射

    常用的映射注解:

    @Property
    @ConstructorArgs @Arg
    @TypeDsicriminator @Case
    @Results @Result
    @MapKey
    @Insert @Update @Delete @Select
    @InsertProvide @UpdateProvider @DeleteProvider @SelectProvider
    @ResultMap @ResultType @SelectKey
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    三、动态sql

    后端和数据库的交互通常需要附加不同的查询条件

    1.if

    通过if判断来选择是否加入额外的sql语句

    <select id="findActiveBlogLike"
         resultType="Blog">
      SELECT * FROM BLOG WHERE state = ‘ACTIVE’
      <if test="title != null">
        AND title like #{title}
      if>
      <if test="author != null and author.name != null">
        AND author_name like #{author.name}
      if>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.choose,when,otherwise

    类似于switch case语句选择sql语句进行执行

    <select id="findActiveBlogLike"
         resultType="Blog">
      SELECT * FROM BLOG WHERE state = ‘ACTIVE’
      <choose>
        <when test="title != null">
          AND title like #{title}
        when>
        <when test="author != null and author.name != null">
          AND author_name like #{author.name}
        when>
        <otherwise>
          AND featured = 1
        otherwise>
      choose>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.where, trim, set

    当where从句中不存在任何一个结果必定返回时,使用上面的if,choose可能都会很尴尬,但是where标签可以自动去掉最前面的AND,并且只有当子结果中返回至少一个结果时加入WHERE sql语句

    <select id="findActiveBlogLike"
         resultType="Blog">
      SELECT * FROM BLOG
      <where>
        <if test="state != null">
             state = #{state}
        if>
        <if test="title != null">
            AND title like #{title}
        if>
        <if test="author != null and author.name != null">
            AND author_name like #{author.name}
        if>
      where>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    类似的解决方案也有set

    <update id="updateAuthorIfNecessary">
      update Author
        <set>
          <if test="username != null">username=#{username},if>
          <if test="password != null">password=#{password},if>
          <if test="email != null">email=#{email},if>
          <if test="bio != null">bio=#{bio}if>
        set>
      where id=#{id}
    update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果where和set的行为无法满足要求,可以用定制的trim语句,对where的定制如下,prefix表示满足某个条件时加入的sql语句,prefixoerrides表示要删掉的前缀,文档提到这里的AND 必须要加空格,应该是为了满足管道分隔符的格式

    <trim prefix="WHERE" prefixOverrides="AND |OR ">
      ...
    trim>
    
    • 1
    • 2
    • 3

    4.foreach

    foreach主要是用来判断表项是否在某个集合中的,其中item和index用来描述java对象的内容和下标,collection表示集合类型,open后的内容指定sql的内容,包括

    <select id="selectPostIn" resultType="domain.blog.Post">
      SELECT *
      FROM POST P
      <where>
        <foreach item="item" index="index" collection="list"
            open="ID in (" separator="," close=")" nullable="true">
              #{item}
        foreach>
      where>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    Linux--Redis 群集
    如何将系统盘MBR转GPT?无损教程分享!
    .Net与AI的强强联合:AntSK知识库项目中Rerank模型的技术突破与实战应用
    pgpool-II 4.3 中文手册-前言
    如何实现 MongoDB join mysql
    卫龙辣条第三次冲刺上市:业绩增速下滑,刘卫平、刘福平提前套现
    用Tinyproxy搭建自己的proxy server
    统一最小二乘标准问题形式
    Japan Registry Services (JPRS) Programming Contest 2024 (AtCoder Beginner Contest 339)
    【2022改良版】学法减分助手PRO小程序源码
  • 原文地址:https://blog.csdn.net/qq_36993218/article/details/126658941