• SSM - Springboot - MyBatis-Plus 全栈体系(十五)


    第三章 MyBatis

    二、MyBatis 基本使用

    4. CRUD 强化练习

    4.1 准备数据库数据
    • 首先,我们需要准备一张名为 user 的表。该表包含字段 id(主键)、username、password。创建SQL如下:
    CREATE TABLE `user` (
      `id` INT(11) NOT NULL AUTO_INCREMENT,
      `username` VARCHAR(50) NOT NULL,
      `password` VARCHAR(50) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    4.2 实体类准备
    • 接下来,我们需要定义一个实体类 User,来对应 user 表的一行数据。
    @Data //lombok
    public class User {
      private Integer id;
      private String username;
      private String password;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    4.3 Mapper接口定义
    • 定义一个 Mapper 接口 UserMapper,并在其中添加 user 表的增、删、改、查方法。
    public interface UserMapper {
      
      int insert(User user);
    
      int update(User user);
    
      int delete(Integer id);
    
      User selectById(Integer id);
    
      List<User> selectAll();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    4.4 MapperXML编写
    • 在 resources /mappers目录下创建一个名为 UserMapper.xml 的 XML 文件,包含与 Mapper 接口中相同的五个 SQL 语句,并在其中,将查询结果映射到 User 实体中。
    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.alex.mapper.UserMapper">
      
      <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO user(username, password)
                    VALUES(#{username}, #{password})
      insert>
      
      <update id="update">
        UPDATE user SET username=#{username}, password=#{password}
        WHERE id=#{id}
      update>
      
      <delete id="delete">
        DELETE FROM user WHERE id=#{id}
      delete>
      
      <select id="selectById" resultType="user">
        SELECT id, username, password FROM user WHERE id=#{id}
      select>
      
      
      <select id="selectAll" resultType="user">
        SELECT id, username, password FROM user
      select>
      
    mapper>
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    4.5 MyBatis配置文件
    • 位置:resources: mybatis-config.xml
    
    DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
        <settings>
            
            <setting name="mapUnderscoreToCamelCase" value="true"/>
            
            <setting name="logImpl" value="SLF4J"/>
        settings>
    
        <typeAliases>
            
            <package name="com.alex.pojo"/>
        typeAliases>
    
        
        <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-example"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                dataSource>
            environment>
        environments>
    
        <mappers>
            
            
            
            
            <mapper resource="mappers/UserMapper.xml"/>
        mappers>
    
    configuration>
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    4.6 效果测试
    package com.alex.test;
    
    import com.alex.mapper.UserMapper;
    import com.alex.pojo.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    
    import java.io.IOException;
    import java.util.List;
    
    /**
     * projectName: com.alex.test
     */
    public class MyBatisTest {
    
        private SqlSession session;
        // junit会在每一个@Test方法前执行@BeforeEach方法
    
        @BeforeEach
        public void init() throws IOException {
            session = new SqlSessionFactoryBuilder()
                    .build(
                            Resources.getResourceAsStream("mybatis-config.xml"))
                    .openSession();
        }
    
        @Test
        public void createTest() {
            User user = new User();
            user.setUsername("admin");
            user.setPassword("123456");
            UserMapper userMapper = session.getMapper(UserMapper.class);
            userMapper.insert(user);
            System.out.println(user);
        }
    
        @Test
        public void updateTest() {
            UserMapper userMapper = session.getMapper(UserMapper.class);
            User user = userMapper.selectById(1);
            user.setUsername("root");
            user.setPassword("111111");
            userMapper.update(user);
            user = userMapper.selectById(1);
            System.out.println(user);
        }
    
        @Test
        public void deleteTest() {
            UserMapper userMapper = session.getMapper(UserMapper.class);
            userMapper.delete(1);
            User user = userMapper.selectById(1);
            System.out.println("user = " + user);
        }
    
        @Test
        public void selectByIdTest() {
            UserMapper userMapper = session.getMapper(UserMapper.class);
            User user = userMapper.selectById(1);
            System.out.println("user = " + user);
        }
    
        @Test
        public void selectAllTest() {
            UserMapper userMapper = session.getMapper(UserMapper.class);
            List<User> userList = userMapper.selectAll();
            System.out.println("userList = " + userList);
        }
    
        // junit会在每一个@Test方法后执行@@AfterEach方法
        @AfterEach
        public void clear() {
            session.commit();
            session.close();
        }
    }
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    5. mapperXML 标签总结

    • MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。

    • SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

      • insert – 映射插入语句。
      • update – 映射更新语句。
      • delete – 映射删除语句。
      • select – 映射查询语句。
    5.1 select 标签
    • MyBatis 在查询和结果映射做了相当多的改进。一个简单查询的 select 元素是非常简单:
    <select id="selectPerson" 
    resultType="hashmap" resultMap="自定义结构"> SELECT * FROM PERSON WHERE ID = #{id} select>
    
    • 1
    • 2
    • 这个语句名为 selectPerson,接受一个 int(或 Integer)类型的参数,并返回一个 HashMap 类型的对象,其中的键是列名,值便是结果行中的对应值。
    • 注意参数符号:#{id} ${key}
    • MyBatis 创建一个预处理语句(PreparedStatement)参数,在 JDBC 中,这样的一个参数在 SQL 中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:
    // 近似的 JDBC 代码,非 MyBatis 代码...
    String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
    PreparedStatement ps = conn.prepareStatement(selectPerson);
    ps.setInt(1,id);
    
    • 1
    • 2
    • 3
    • 4
    • select 元素允许你配置很多属性来配置每条语句的行为细节:
    属性描述
    id在命名空间中唯一的标识符,可以被用来引用这条语句。
    resultType期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
    resultMap对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。
    timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
    statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
    5.2 insert, update 和 delete 标签
    • 数据变更语句 insert,update 和 delete 的实现非常接近:
    <insert
      id="insertAuthor"
      statementType="PREPARED"
      keyProperty=""
      keyColumn=""
      useGeneratedKeys=""
      timeout="20">
    
    <update
      id="updateAuthor"
      statementType="PREPARED"
      timeout="20">
    
    <delete
      id="deleteAuthor"
      statementType="PREPARED"
      timeout="20">
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    属性描述
    id在命名空间中唯一的标识符,可以被用来引用这条语句。
    timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
    statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
    useGeneratedKeys(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
    keyProperty(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
    keyColumn(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。

    三、MyBatis 多表映射

    1. 多表映射概念

    1.1 多表查询结果映射思路
    • 上面讲解了单表的mybatis操作!但是开发中更多的是多表查询需求,这种情况我们如何该如何进行处理?
    • MyBatis 思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样。 如果能有一种数据库映射模式,完美适配所有的应用程序查询需求,那就太好了,而 ResultMap 就是 MyBatis 就是完美答案。
    • 官方例子:我们如何映射下面这个语句?
    
    <select id="selectBlogDetails" resultMap="detailedBlogResultMap">
      select
           B.id as blog_id,
           B.title as blog_title,
           B.author_id as blog_author_id,
           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,
           A.favourite_section as author_favourite_section,
           P.id as post_id,
           P.blog_id as post_blog_id,
           P.author_id as post_author_id,
           P.created_on as post_created_on,
           P.section as post_section,
           P.subject as post_subject,
           P.draft as draft,
           P.body as post_body,
           C.id as comment_id,
           C.post_id as comment_post_id,
           C.name as comment_name,
           C.comment as comment_text,
           T.id as tag_id,
           T.name as tag_name
      from Blog B
           left outer join Author A on B.author_id = A.id
           left outer join Post P on B.id = P.blog_id
           left outer join Comment C on P.id = C.post_id
           left outer join Post_Tag PT on PT.post_id = P.id
           left outer join Tag T on PT.tag_id = T.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
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 你可能想把它映射到一个智能的对象模型,这个对象表示了一篇博客,它由某位作者所写,有很多的博文,每篇博文有零或多条的评论和标签。 我们先来看看下面这个完整的例子,它是一个非常复杂的结果映射(假设作者,博客,博文,评论和标签都是类型别名)。 虽然它看起来令人望而生畏,但其实非常简单。
    <!-- 非常复杂的结果映射 -->
    <resultMap id="detailedBlogResultMap" type="Blog">
      <constructor>
        <idArg column="blog_id" javaType="int"/>
      </constructor>
      <result property="title" column="blog_title"/>
      <association property="author" javaType="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"/>
        <result property="favouriteSection" column="author_favourite_section"/>
      </association>
      <collection property="posts" ofType="Post">
        <id property="id" column="post_id"/>
        <result property="subject" column="post_subject"/>
        <association property="author" javaType="Author"/>
        <collection property="comments" ofType="Comment">
          <id property="id" column="comment_id"/>
        </collection>
        <collection property="tags" ofType="Tag" >
          <id property="id" column="tag_id"/>
        </collection>
      </collection>
    </resultMap>
    
    • 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
    • 现在可能看不懂,接下来要学习将多表查询结果使用ResultMap标签映射到实体类对象上!
    • 目标:
      • 多表查询语句使用
      • 多表结果承接实体类设计
      • 使用ResultMap完成多表结果映射
    1.2 实体类设计方案
    1.2.1 多表关系回顾:(双向查看)
    • 一对一
      • 夫妻关系,人和身份证号
    • 一对多| 多对一
      • 用户和用户的订单,锁和钥匙
    • 多对多
      • 老师和学生,部门和员工
    1.2.2 实体类设计关系(查询):(单向查看)
    1.2.2.1 对一
    • 对一 : 夫妻一方对应另一方,订单对应用户都是对一关系

    • 实体类设计:对一关系下,类中只要包含单个对方对象类型属性即可!

    public class Customer {
    
      private Integer customerId;
      private String customerName;
    
    }
    
    public class Order {
    
      private Integer orderId;
      private String orderName;
      private Customer customer;// 体现的是对一的关系
    
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1.2.2.2 对多
    • 对多: 用户对应的订单,讲师对应的学生或者学生对应的讲师都是对多关系
    • 实体类设计:对多关系下,类中只要包含对方类型集合属性即可!
    public class Customer {
    
      private Integer customerId;
      private String customerName;
      private List<Order> orderList;// 体现的是对多的关系
    }
    
    public class Order {
    
      private Integer orderId;
      private String orderName;
      private Customer customer;// 体现的是对一的关系
      
    }
    
    //查询客户和客户对应的订单集合  不要管!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1.2.3 多表结果实体类设计小技巧:
    • 对一,属性中包含对方对象
    • 对多,属性中包含对方对象集合
    • 只有真实发生多表查询时,才需要设计和修改实体类,否则不提前设计和修改实体类!
    • 无论多少张表联查,实体类设计都是两两考虑!
    • 在查询映射的时候,只需要关注本次查询相关的属性!例如:查询订单和对应的客户,就不要关注客户中的订单集合!
    1.3 多表映射案例准备
    1.3.1 数据库
    CREATE TABLE `t_customer` (`customer_id` INT NOT NULL AUTO_INCREMENT, `customer_name` CHAR(100), PRIMARY KEY (`customer_id`) );
    
    CREATE TABLE `t_order` ( `order_id` INT NOT NULL AUTO_INCREMENT, `order_name` CHAR(100), `customer_id` INT, PRIMARY KEY (`order_id`) ); 
    
    INSERT INTO `t_customer` (`customer_name`) VALUES ('c01');
    
    INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o1', '1');
    INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o2', '1');
    INSERT INTO `t_order` (`order_name`, `customer_id`) VALUES ('o3', '1'); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 实际开发时,一般在开发过程中,不给数据库表设置外键约束。
    • 原因是避免调试不方便。
    • 一般是功能开发完成,再加外键约束检查是否有bug。
    1.3.2 实体类设计
    • 稍后会进行订单关联客户查询,也会进行客户关联订单查询,所以在这先练习设计
    @Data
    public class Customer {
    
      private Integer customerId;
      private String customerName;
      private List<Order> orderList;// 体现的是对多的关系
      
    }  
    
    @Data
    public class Order {
    
      private Integer orderId;
      private String orderName;
      private Customer customer;// 体现的是对一的关系
      
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    Linux:mongodb数据库源码包安装(4.4.25版本)
    运行jar时提示缺少依赖的类
    解决matlab报错“输入参数的数目不足”
    git ssh permission denied解决办法
    【无人机】无人机的气象数据采集系统设计(Matlab代码实现)
    stable diffusion 零基础入门教程
    第十五届蓝桥杯物联网试题(国赛)
    VHDL菜鸟入门到精通之激励文件编写
    洗地机选购攻略,洗地机哪个品牌好?一篇教会你挑到好用的洗地机
    什么是Linux
  • 原文地址:https://blog.csdn.net/sgsgkxkx/article/details/133364865