Mybatis

MyBatis(下篇)


1.多表映射

**前言:**MyBatis 思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样。 如果能有一种数据库映射模式,完美适配所有的应用程序查询需求,那就太好了,而 ResultMap 就是 MyBatis 就是完美答案。

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

**对多实体类设计思路:**在对多关系下,类中只要包含对方类型集合属性即可

只有真实发生多表查询时,才需要设计和修改实体类,否则不提前设计和修改实体类!

无论多少张表联查,实体类设计都是两两考虑!

在查询映射的时候,只需要关注本次查询相关的属性!例如:查询订单和对应的客户,就不要关注客户中的订单集合!

1.1对一查询

在resultMap中给对象属性赋值时,使用association标签进行赋值

  • property:对象属性的属性名

  • column:数据表中的列名

  • javaType:对象属性的类型的全限定符或全限定符的别名

  • association标签:对一关系映射标签

  • id标签:声明主键列的映射关系

  • result标签:声明非主键列的映射关系

sql 复制代码
========================数据库sql语句准备===================================
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'); 
复制代码
java 复制代码
=======================对应多表查询实体类设计================================
@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;// 体现的是对一的关系
  
}  
复制代码
java 复制代码
=======================Mapper接口方法的声明=================================
public interface OrderMapper {
  Order selectOrderWithCustomer(Integer orderId);
}
XML 复制代码
=====================Mapper.xml文件编写====================================
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "<https://mybatis.org/dtd/mybatis-3-mapper.dtd>">
<mapper namespace="com.ergou.mapper.OrderMapper">
<!-- 创建resultMap实现"对一"关联关系映射 -->
<!-- id属性:通常设置为这个resultMap所服务的那条SQL语句的id加上"ResultMap" -->
<!-- type属性:要设置为这个resultMap所服务的那条SQL语句最终要返回的类型 -->
<resultMap id="selectOrderWithCustomerResultMap" type="order">
​
  <!-- 先设置Order自身属性和字段的对应关系 -->
  <id column="order_id" property="orderId"/>
​
  <result column="order_name" property="orderName"/>
​
  <!-- 使用association标签配置"对一"关联关系 -->
  <!-- property属性:在Order类中对一的一端进行引用时使用的属性名 -->
  <!-- javaType属性:一的一端类的全类名 -->
  <association property="customer" javaType="customer">
​
    <!-- 配置Customer类的属性和字段名之间的对应关系 -->
    <id column="customer_id" property="customerId"/>
    <result column="customer_name" property="customerName"/>
​
  </association>
​
</resultMap>
​
<!-- Order selectOrderWithCustomer(Integer orderId); -->
<select id="selectOrderWithCustomer" resultMap="selectOrderWithCustomerResultMap">
​
  SELECT order_id,order_name,c.customer_id,customer_name
  FROM t_order o
  LEFT JOIN t_customer c
  ON o.customer_id=c.customer_id
  WHERE o.order_id=#{orderId}
​
</select>
</mapper>

1.2对多映射

1.一对多使用collection子标签进行关联多方Order

<collection property="指定 Java 对象中集合属性的名称" javaType="指定集合本身的类型(如 `List`, `Set` 等)" ofType="指定集合中元素的类型" autoMapping="true"> </collection> 2.属性:

1)property="orders" 这里的orders表示User类的成员变量orders

2)javaType="List" 表示User类的成员变量orders存储的Order对象使用的类型,这里是List 一般不书写,通常,MyBatis 能够根据 ofType 自动推断出合适的 javaType

  1. ofType="Order" 表示List集合中存储数据的类型 Order 3.一定要记住这里给user表的id起别名是uid,order表的id起别名是oid.在resultMap标签的id子标签中的column属性值书写对应的uid和oid
XML 复制代码
<!-- 配置resultMap实现从Customer到OrderList的"对多"关联关系 -->
<resultMap id="selectCustomerWithOrderListResultMap"
​
  type="customer">
​
  <!-- 映射Customer本身的属性 -->
  <id column="customer_id" property="customerId"/>
​
  <result column="customer_name" property="customerName"/>
​
  <!-- collection标签:映射"对多"的关联关系 -->
  <!-- property属性:在Customer类中,关联"多"的一端的属性名 -->
  <!-- ofType属性:集合属性中元素的类型 -->
  <collection property="orderList" ofType="order">
​
    <!-- 映射Order的属性 -->
    <id column="order_id" property="orderId"/>
​
    <result column="order_name" property="orderName"/>
​
  </collection>
​
</resultMap>
​
<!-- Customer selectCustomerWithOrderList(Integer customerId); -->
<select id="selectCustomerWithOrderList" resultMap="selectCustomerWithOrderListResultMap">
  SELECT c.customer_id,c.customer_name,o.order_id,o.order_name
  FROM t_customer c
  LEFT JOIN t_order o
  ON c.customer_id=o.customer_id
  WHERE c.customer_id=#{customerId}
</select>
复制代码

多表映射配置优化

setting属性 属性含义 可选值 默认值
autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 NONE, PARTIAL, FULL PARTIAL
关联关系 配置项关键词 所在配置文件和具体位置
对一 ①association标签:对一关系映射标签②javaType属性:对象属性的类型③column属性:数据表中的列名④property属性:映射的属性名 Mapper配置文件中的resultMap标签内
对多 ①collection标签:对多关系映射标签②ofType属性:集合中存储的数据类型③column属性:数据表中的列名④property属性:映射的属性名 Mapper配置文件的resultMap标签内

有用的mybatis配置设置

①logImpl:开启控制台的日志输出功能,可以看到后台执行的sql语句

②mapUnderscoreToCamelCase:自动开启驼峰式映射(不适合嵌套)

③autoMappingBehavior:自动映射字段和属性(适用多层嵌套)

④typeAliases:自动类型别名转换

XML 复制代码
<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <setting name="autoMappingBehavior" value="FULL"/>
</settings>
​
​
<typeAliases>
        <package name="com.atguigu.pojo"/>
</typeAliases>
<typeAliases>
        <typeAlias type="com.atguigu.pojo.Employee" alias="huermosi"/>
</typeAliases>

2.动态语句

前言 :动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

if和where标签

①if标签

可以让我们有选择的加入Sql语句的片段。

在if标签的test属性里面,可以访问实体类的属性,不可以访问数据库表的字段

若test标签里面内容为true则添加if标签里面的语句

②where标签

可以帮助我们自动去掉"标签里面多余的and/or",自动连接where关键字,防止报错

XML 复制代码
<select id="queryByNameAndSalary" resultType="com.ergou.pojo.Employee">
    SELECT * FROM t_emp
    <where>
    <if test="name != null">
        emp_name = #{name}
    </if>
    <if test="salary != null and salary &gt; 100">
        AND emp_salary = #{salary}
    </if>
    </where>
</select>

set标签

自动去掉多余的逗号,自动连接set关键字

XML 复制代码
<update id="update">
    UPDATE t_emp 
    <set>
        <if test="empName != null">
            emp_name = #{empName},
        </if>
        <if test="empSalary != null">
            emp_salary = #{empSalary}
        </if>
    </set>
    WHERE emp_id = #{empId}
</update>

trim标签

  • prefix属性:指定要动态添加的前缀

  • suffix属性:指定要动态添加的后缀

  • prefixOverrides属性:指定要动态去掉的前缀,使用"|"分隔有可能的多个值

  • suffixOverrides属性:指定要动态去掉的后缀,使用"|"分隔有可能的多个值

XML 复制代码
 <select id="querytrim" resultType="employee">
        <trim prefix="where" prefixOverrides="and | or">
            <if test="name!=null">
                emp_name=#{name}
            </if>
​
            <if test="salary!=null and salary &gt; 100">
                and emp_salary=#{salary}
            </if>
        </trim>
    </select>
==========================================================================
    <update id="updatatrim" >
        updata t_emp
​
        <trim prefix="set" suffixOverrides=",">
            <if test="empName!=null">
                emp_name=#{empName},
            </if>
​
            <if test="empSalary!=null">
                emp_salary=#{empSalary}
            </if>
        </trim>
        where emp_id=#{empId}
​
    </update>

choose/when/otherwise标签

  • 从上到下依次执行条件判断

  • 遇到的第一个满足条件的分支会被采纳

  • 被采纳分支后面的分支都将不被考虑

  • 如果所有的when分支都不满足,那么就执行otherwise分支

XML 复制代码
<!-- List<Employee> selectEmployeeByConditionByChoose(Employee employee) -->
<select id="selectEmployeeByConditionByChoose" resultType="com.atguigu.mybatis.entity.Employee">
    select emp_id,emp_name,emp_salary from t_emp
    where
    <choose>
        <when test="empName != null">emp_name=#{empName}</when>
        <when test="empSalary &lt; 3000">emp_salary &lt; 3000</when>
        <otherwise>1=1</otherwise>
    </choose>
    
</select>

foreach标签

①collection属性 :指定要遍历的集合

②item属性: 遍历集合的过程中能得到每一个具体对象,在item属性中设置一个名字,将来通过这个名字引用遍历出来的对象

③separator属性 :指定当foreach标签的标签体重复拼接字符串时,各个标签体字符串之间的分隔符

④open属性: 指定整个循环把字符串拼好后,字符串整体的前面要添加的字符串

⑤close属性: 指定整个循环把字符串拼好后,字符串整体的后面要添加的字符串

XML 复制代码
<select id="querybatch" resultType="employee">
        select * from t_emp
        where emp_id in
        <foreach collection="ids" open="(" separator="," close=")" item="id">
            #{id}
        </foreach>
    </select>
​
​
    <delete id="deletebatch" >
        delete from t_emp
        where emp_id in
        <foreach collection="ids" open="(" separator="," close=")" item="id">
            #{id}
        </foreach>
    </delete>
            
            
    <insert id="insertbatch" >
        insert into t_emp(emp_name,emp_salary)
        values
        <foreach collection="list" separator="," item="employee">
            (#{employee.empName},#{employee.empSalary})
        </foreach>
    </insert>
    
<!-- 如果一个标签涉及到多条执行sql语句,一定要在mybatis的配置中打开多语句执行权限-->            
    <update id="updatebatch" >
      <foreach collection="list" item="emp">
          update t_emp set emp_name=#{emp.empName},emp_salary=#{emp.empSalary}
          where emp_id=#{emp.empId}
      </foreach>
    </update>
XML 复制代码
在mybatis中开启多语句执行权限
atguigu.dev.url=jdbc:mysql:///mybatis-example?allowMultiQueries=true

sql片段

作用: 提取出重复的sql语句,方便以后调用,简化代码量

标签:<sql></sql>

XML 复制代码
<!-- 使用sql标签抽取重复出现的SQL片段 -->
<sql id="mySelectSql">
    select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
</sql>
​
​
<!-- 使用include标签引用声明的SQL片段 -->
<include refid="mySelectSql"/>

3.高级扩展

3.1批量扫描mapper接口

要求:

1.要求Mapperxml文件和mapper接口的命名必须相同

2.最终打包的位置要一致,都是在指定的包地址下面

①将xml文件放到mapper接口所在的包下

②在resource文件夹下创建与mapper接口相同的文件夹结构

XML 复制代码
<mappers>
    <package name="com.atguigu.mapper"/>
</mappers>

3.2插件

插件可以在用于语句执行过程中进行拦截,并允许通过自定义处理程序来拦截和修改 SQL 语句、映射语句的结果等。

MyBatis 的插件机制包括以下三个组件:

①Interceptor(拦截器):定义一个拦截方法 intercept,该方法在执行 SQL 语句、执行查询、查询结果的映射时会被调用。

②Invocation(调用):实际上是对被拦截的方法的封装,封装了 Object target、Method method 和 Object[] args 这三个字段。

③InterceptorChain(拦截器链):对所有的拦截器进行管理,包括将所有的 Interceptor 链接成一条链,并在执行 SQL 语句时按顺序调用。

分页插件(PageHelper):

导入依赖(pom.xml):

XML 复制代码
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.11</version>
</dependency>
复制代码

配置分页插件(MyBatis-config.xml):

1com.github.pagehelper.PageInterceptor:插件名称

2Dialect:指定数据库类型

XML 复制代码
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <property name="helperDialect" value="mysql"/>
    </plugin>
</plugins>
​

插件的使用:

java 复制代码
@Test
public void testTeacherRelationshipToMulti() {
​
    TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
​
    PageHelper.startPage(1,2);
    // 查询Customer对象同时将关联的Order集合查询出来
    List<Teacher> allTeachers = teacherMapper.findAllTeachers();
//
    PageInfo<Teacher> pageInfo = new PageInfo<>(allTeachers);
​
    System.out.println("pageInfo = " + pageInfo);
    long total = pageInfo.getTotal(); // 获取总记录数
    System.out.println("total = " + total);
    int pages = pageInfo.getPages();  // 获取总页数
    System.out.println("pages = " + pages);
    int pageNum = pageInfo.getPageNum(); // 获取当前页码
    System.out.println("pageNum = " + pageNum);
    int pageSize = pageInfo.getPageSize(); // 获取每页显示记录数
    System.out.println("pageSize = " + pageSize);
    List<Teacher> teachers = pageInfo.getList(); //获取查询页的数据集合
    System.out.println("teachers = " + teachers);
    teachers.forEach(System.out::println);
​
}

3.3逆向工程

MyBatis 的逆向工程是一种自动化生成持久层代码和映射文件的工具,它可以根据数据库表结构和设置的参数生成对应的实体类、Mapper.xml 文件、Mapper 接口等代码文件,简化了开发者手动生成的过程。逆向工程使开发者可以快速地构建起 DAO 层,并快速上手进行业务开发。 MyBatis 的逆向工程有两种方式:通过 MyBatis Generator 插件实现和通过 Maven 插件实现。无论是哪种方式,逆向工程一般需要指定一些配置参数,例如数据库连接 URL、用户名、密码、要生成的表名、生成的文件路径等等。 总的来说,MyBatis 的逆向工程为程序员提供了一种方便快捷的方式,能够快速地生成持久层代码和映射文件,是半自动 ORM 思维像全自动发展的过程,提高程序员的开发效率。

注意:逆向工程只能生成单表crud的操作,多表查询依然需要我们自己编写!

逆向工程插件MyBatisX使用

MyBatisX 是一个 MyBatis 的代码生成插件,可以通过简单的配置和操作快速生成 MyBatis Mapper、pojo 类和 Mapper.xml 文件。下面是使用 MyBatisX 插件实现逆向工程的步骤:

  • 安装插件:在Intellij IDEA中打开插件市场,搜索MyBatisX并进行安装

  • 使用Intellij IDEA连接数据库

  • 填写信息

  • 展示数据库

  • 逆向工程使用

  • 效果展示

相关推荐
ggdpzhk2 小时前
idea 编辑竖列:alt +shift+insert
java·ide·intellij-idea
hikktn2 小时前
Java 兼容读取WPS和Office图片,结合EasyExcel读取单元格信息
java·开发语言·wps
迪迦不喝可乐2 小时前
软考 高级 架构师 第十一章 面向对象分析 设计模式
java·设计模式
檀越剑指大厂3 小时前
【Java基础】使用Apache POI和Spring Boot实现Excel文件上传和解析功能
java·spring boot·apache
苹果酱05673 小时前
Golang的网络流量分配策略
java·spring boot·毕业设计·layui·课程设计
小青柑-3 小时前
Go语言中的接收器(Receiver)详解
开发语言·后端·golang
孑么3 小时前
GDPU Android移动应用 重点习题集
android·xml·java·okhttp·kotlin·android studio·webview
未命名冀4 小时前
微服务面试相关
java·微服务·面试
Heavydrink4 小时前
ajax与json
java·ajax·json
阿智智4 小时前
纯手工(不基于maven的pom.xml、Web容器)连接MySQL数据库的详细过程(Java Web学习笔记)
java·mysql数据库·纯手工连接