MyBatis快速入门(中)

MyBatis快速入门(中)

  • 四、全局配置文件configuration标签中子标签顺序
    • 1、子标签顺序
    • 2、子标签说明
    • 3、`<properties>` 标签和 `<environments>` 标签详述
    • 4、配置文件代码示例
  • 五、MyBatis 基础功能之 resultMap
    • 1、建表语句
    • 2、解决表中字段名和类中属性名不一致
      • (1)配置 驼峰命名转换
      • (2)使用别名 AS 配合字段映射
      • (3)使用 @Results 和 @Result 注解
      • (4)使用 Map 类型
      • (5)使用 `<resultMap>` 配置全局映射
    • 3、resultMap 映射
      • (1)字段映射
      • (2)多对一关联映射
        • (a)使用 `AS` 别名 (as 可省略)
        • (b)resultMap 级联属性赋值
        • (c)使用 association 标签定义关联的单个对象的封装
        • (d)association 分段查询
          • (😀)分步查询之延迟加载(按需加载)
          • (😀)lazyLoadingEnabled 与 aggressiveLazyLoading
      • (3)一对多关联映射
        • (a)使用 collocation 处理一对多的映射关系
        • (b)使用 collocation 分步查询
  • 五、MyBatis 基础功能之动态 SQL
    • if
    • where
    • trim
    • choose...when...otherwise
    • foreach
    • sql
    • set


官方文档


四、全局配置文件configuration标签中子标签顺序

mybatis全局配置文件mybatis-config.xml中的 configuration 标签中可以配置各种功能的子标签,但是这些子标签是有顺序要求的,确保配置文件结构正确,且每个标签都按照MyBatis规范的顺序放置,这样可以避免配置错误。

1、子标签顺序

在这里插入图片描述


2、子标签说明


  • <properties>:用于加载外部文件,包含 数据库连接信息,避免配置直接在配置文件中硬编码。

  • <settings>全局设置,用于控制MyBatis的行为,比如 是否启用驼峰配置、延迟加载和缓存

  • <typeAliases>定义类型别名,简化类的引用。例如,User别名代表com.example.model.User类。

  • <typeHandlers>配置自定义类型处理器,用于特殊类型的转换。

  • <objectFactory>自定义对象工厂,用于创建对象的自定义逻辑。

  • <objectWrapperFactory>自定义对象包装工厂,用于处理复杂对象的包装。

  • <reflectorFactory>自定义引用工厂,用于创建引用对象的工厂。

  • <plugins>插件配置,用于拦截SQL执行、结果映射等。

  • <environments>环境配置,用于定义不同的数据库环境,例如开发环境、测试环境等。

  • <databaseIdProvider>:数据库ID提供器,用于根据不同的数据库类型切换配置。

  • <mappers>:定义Mapper配置,可以是XML文件路径或Mapper接口所在的包路径。


3、<properties> 标签和 <environments> 标签详述


MyBatis 中,<properties> 标签和 <environments> 标签都可以包含数据库连接信息,但它们的使用目的和方式有所不同:

在这里插入图片描述
假设有一个database.properties文件,不同环境的数据库连接信息分别如下:

jdbc.driver=com.mysql.cj.jdbc.Driver

# 开发环境
dev.jdbc.url=jdbc:mysql://localhost:3306/dev_db
dev.jdbc.username=dev_user
dev.jdbc.password=dev_password

# 测试环境
test.jdbc.url=jdbc:mysql://localhost:3306/test_db
test.jdbc.username=test_user
test.jdbc.password=test_password

# 生产环境
prod.jdbc.url=jdbc:mysql://localhost:3306/prod_db
prod.jdbc.username=prod_user
prod.jdbc.password=prod_password

MyBatis配置文件中使用<properties>加载这些属性,再通过<environments>使用这些属性值:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 加载外部的数据库属性文件 -->
    <properties resource="database.properties"/>

    <!-- 配置不同的数据库环境 -->
    <environments default="development">
        
        <!-- 开发环境 -->
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${dev.jdbc.url}"/>
                <property name="username" value="${dev.jdbc.username}"/>
                <property name="password" value="${dev.jdbc.password}"/>
            </dataSource>
        </environment>

        <!-- 测试环境 -->
        <environment id="testing">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${test.jdbc.url}"/>
                <property name="username" value="${test.jdbc.username}"/>
                <property name="password" value="${test.jdbc.password}"/>
            </dataSource>
        </environment>

        <!-- 生产环境 -->
        <environment id="production">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${prod.jdbc.url}"/>
                <property name="username" value="${prod.jdbc.username}"/>
                <property name="password" value="${prod.jdbc.password}"/>
            </dataSource>
        </environment>

    </environments>

    <!-- 其他配置项 -->
</configuration>


4、配置文件代码示例

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <!-- 1. properties: 配置属性,可选 -->
    <properties resource="database.properties">
        <property name="jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbc.url" value="jdbc:mysql://localhost:3306/mydatabase"/>
        <property name="jdbc.username" value="root"/>
        <property name="jdbc.password" value="password"/>
    </properties>

    <!-- 2. settings: 全局设置,可选 -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="cacheEnabled" value="true"/>
    </settings>

    <!-- 3. typeAliases: 类型别名定义,可选 -->
    <typeAliases>
        <typeAlias alias="User" type="com.example.model.User"/>
    </typeAliases>

    <!-- 4. typeHandlers: 自定义类型处理器配置,可选 -->
    <typeHandlers>
        <typeHandler handler="com.example.typehandler.CustomTypeHandler"/>
    </typeHandlers>

    <!-- 5. objectFactory: 自定义对象工厂配置,可选 -->
    <objectFactory type="com.example.factory.CustomObjectFactory">
        <property name="someProperty" value="someValue"/>
    </objectFactory>

    <!-- 6. objectWrapperFactory: 自定义对象包装工厂,可选 -->
    <objectWrapperFactory type="com.example.factory.CustomObjectWrapperFactory"/>

    <!-- 7. reflectorFactory: 自定义反射工厂配置,可选 -->
    <reflectorFactory type="com.example.factory.CustomReflectorFactory"/>

    <!-- 8. plugins: 插件配置,可选 -->
    <plugins>
        <plugin interceptor="com.example.plugin.LoggingInterceptor"/>
    </plugins>

    <!-- 9. environments: 数据库环境配置,必选 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 10. databaseIdProvider: 数据库 ID 提供器,可选 -->
    <databaseIdProvider type="DB_VENDOR">
        <property name="MySQL" value="mysql"/>
        <property name="Oracle" value="oracle"/>
    </databaseIdProvider>

    <!-- 11. mappers: Mapper 配置,可选 -->
    <mappers>
        <mapper resource="com/example/mapper/UserMapper.xml"/>
        <package name="com.example.mapper"/>
    </mappers>

</configuration>

五、MyBatis 基础功能之 resultMap

MyBatis中,resultMap是一个核心功能,用于将SQL查询结果映射到Java对象上。它提供了一种灵活的方式,将数据库表的字段Java类的属性进行关联,并能够处理复杂的映射需求。本章将通过具体案例来详细展示 resultMap 灵活的映射功能

1、建表语句

-- 创建 t_dept 表
CREATE TABLE t_dept (
    did INT(11) PRIMARY KEY AUTO_INCREMENT,
    dept_name VARCHAR(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;

-- 创建 t_emp 表
CREATE TABLE t_emp (
    eid INT(11) PRIMARY KEY AUTO_INCREMENT,
    emp_name VARCHAR(20) NOT NULL,
    age INT(11),
    sex CHAR(1),
    email VARCHAR(20),
    did INT(11),
    FOREIGN KEY (did) REFERENCES t_dept(did)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;


-- 向 t_dept 表插入 4 个部门数据
INSERT INTO t_dept (dept_name) VALUES ('Human Resources');
INSERT INTO t_dept (dept_name) VALUES ('Finance');
INSERT INTO t_dept (dept_name) VALUES ('Engineering');
INSERT INTO t_dept (dept_name) VALUES ('Marketing');

-- 向 t_emp 表插入 20 个员工数据
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Alice', 30, 'F', 'alice@example.com', 1);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Bob', 25, 'M', 'bob@example.com', 2);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Charlie', 28, 'M', 'charlie@example.com', 3);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Diana', 32, 'F', 'diana@example.com', 4);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Eve', 27, 'F', 'eve@example.com', 3);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Frank', 35, 'M', 'frank@example.com', 1);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('George', 40, 'M', 'george@example.com', 2);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Hannah', 29, 'F', 'hannah@example.com', 4);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Ivan', 31, 'M', 'ivan@example.com', 3);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Julia', 26, 'F', 'julia@example.com', 1);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Kevin', 33, 'M', 'kevin@example.com', 2);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Lily', 22, 'F', 'lily@example.com', 4);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Mike', 37, 'M', 'mike@example.com', 1);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Nina', 28, 'F', 'nina@example.com', 2);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Oscar', 45, 'M', 'oscar@example.com', 3);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Paula', 34, 'F', 'paula@example.com', 4);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Quinn', 30, 'M', 'quinn@example.com', 1);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Rachel', 27, 'F', 'rachel@example.com', 2);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Steve', 39, 'M', 'steve@example.com', 3);
INSERT INTO t_emp (emp_name, age, sex, email, did) VALUES ('Tina', 32, 'F', 'tina@example.com', 4);




-- 将所有男性的 sex 字段更新为 "男"
UPDATE t_emp SET sex = '男' WHERE sex = 'M';

-- 将所有女性的 sex 字段更新为 "女"
UPDATE t_emp SET sex = '女' WHERE sex = 'F';

2、解决表中字段名和类中属性名不一致

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


(1)配置 驼峰命名转换

如果表字段Java 类属性之间存在一致的映射规则(例如下划线驼峰命名规则),可以使用 MyBatis 提供的自动映射功能,使用settings标签在全局配置文件中设置,即配置 驼峰命名转换

<configuration>
    <settings>
        <!-- 开启驼峰命名转换 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>

在这里插入图片描述


(2)使用别名 AS 配合字段映射

也可以在SQL查询中使用别名,使字段名属性名相匹配:

    <!--查询所有员工信息-->
    <select id="getAllEmp" resultType="Emp">
        select eid, emp_name as empName,age,sex,email,did from t_emp
    </select>

在这里插入图片描述


(3)使用 @Results 和 @Result 注解

在映射 SQL 语句时,可以通过 @Results 注解手动指定 字段属性之间的对应关,通过注解可以完全避免使用XML文件

但是这种方式仅适用于简单查询,对于复杂的查询需求,例如动态 SQL批量插入等,建议使用 XML 映射文件,因为 XML 支持更灵活的 SQL 语句构建。

如下示例中,在mapper接口方法中 ,emp_name 数据库字段被映射到 empName 属性,此时就不再需要 EmpMapper.xml映射文件了

public interface EmpMapper {
    /**
     * 查询所有员工信息
     */
    @Select("SELECT * FROM t_emp")
    @Results({
            @Result(property = "empName", column = "emp_name")
    })
    List<Emp> getAllEmp();
}

在这里插入图片描述


(4)使用 Map 类型

如果想要定义明确的类,可以将结果映射到Map类型,这样数据库字段名会直接作为Map存储的键值。

如下示例中,在mapper接口方法中 ,数据库字段名会直接作为Map存储的键值,此时就不再需要 EmpMapper.xml映射文件了

public interface EmpMapper {
    /**
     * 查询所有员工信息
     */
    @Select("SELECT * FROM t_emp")
    List<Map<String, Object>> getAllEmp();
}

注意测试方法接收数据类型

public class EmpMapperTest {
    /**
     * 查询所有员工信息
     */
    @Test
    public void testGetAllEmp() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        List<Map<String, Object>> empList = empMapper.getAllEmp();
        empList.forEach(System.out::println);
    }
}

在这里插入图片描述


(5)使用 <resultMap> 配置全局映射

如果需要更灵活的字段到属性的映射控制,可以在配置文件中通过 <resultMap> 配置全局映射。在 mapper 接口的 XML 映射文件中,可以通过 <resultMap> 手动映射数据库字段和类属性。创建一个通用的映射规则,适用于多个查询。

例如,在 EmpMapper.xml 中定义一个 <resultMap>,然后在其他查询中引用这个 resultMap:例如:

<?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.ningxia.mybatis.mapper.EmpMapper">

 <!-- 定义一个通用的 resultMap -->
    <resultMap id="empResultMap" type="Emp">
        <!-- id 标签 用来设置主键的映射关系-->
        <id property="eid" column="eid"/>
        <!-- result 标签 用来设置普通字段的映射关系-->
        <result property="empName" column="emp_name"/>
        <result property="sex" column="sex"/>
        <result property="email" column="email"/>
        <result property="did" column="did"/>
    </resultMap>

 <!-- 查询时使用 resultMap -->
    <select id="getAllEmp" resultMap="empResultMap">
        select * from t_emp
    </select>
    
</mapper>

在这里插入图片描述

3、resultMap 映射

(1)字段映射

resultMap可以将数据库的字段名Java类的属性名进行映射,特别是在字段名属性名不一致的情况下。

参考示例:本章内容 2-(5)

(2)多对一关联映射

中创建所对应的对象

  • (如下案例:在实体类Emp中创建Dept类型的属性对象)

案例: 根据id 查询员工信息的时候,把员工所在的部门信息也查出来

  • 在这个场景中,一个员工属于一个部门,但一个部门可能有多个员工。员工(Employee)部门(Department)的关系是多对一的; 多个员工指向一个部门,因此这是典型的多对一关系。
  • 实体类
package com.ningxia.mybatis.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    private Integer eid;
    private String empName;
    private Integer age;
    private Character sex;
    private String email;
    private Integer did;
    private Dept dept;// 当关联的是一个对象时,这种多对一的关系,直接在‘多’的一方中创建‘一’所对应的对象
}

-----------------------------------------
package com.ningxia.mybatis.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
    private Integer did;
    private String deptName;
}


(a)使用 AS 别名 (as 可省略)

可以使用多表联查,AS起别名的方式解决这种问题,使用 Map类型接收结果

  • EmpMapper 接口方法
/**
 * 根据员工id查询员工信息和员工所在部门信息
 * <p>
 * 分步查询 根据员工id查询员工信息和员工所在部门信息
 * 1、 先根据员工id查询员工信息
 * 2、 再根据员工信息中的部门id去获取对应的部门信息
 */
Map<String, Object> getEmpAndDeptByIdOne(@Param("id") Integer id);

  • EmpMapper 映射文件
<?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.ningxia.mybatis.mapper.EmpMapper">

    <!--根据员工id查询员工信息和员工所在部门信息 -->
    <!--方式一:多表关联 使用 AS 起别名-->
    <select id="getEmpAndDeptByIdOne" resultType="Map">
        select
        e.eid,
        e.emp_name empName,
        e.age,
        e.sex,
        e.email,
        e.did eDid,
        d.did dDid,
        d.dept_name deptName
        from t_emp e
        left join t_dept d
        on e.did = d.did
        where e.eid = #{id}
    </select>

</mapper>

  • 测试类方法
package com.ningxia.mybatis.test;

import com.ningxia.mybatis.mapper.EmpMapper;
import com.ningxia.mybatis.pojo.Emp;
import com.ningxia.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;
import java.util.Map;

public class EmpMapperTest {

    /**
     * 根据员工id查询员工信息和员工所在部门信息
     * <p>
     * 分步查询 根据员工id查询员工信息和员工所在部门信息
     * 1、 先根据员工id查询员工信息
     * 2、 再根据员工信息中的部门id去获取对应的部门信息
     */
    @Test
    public void testGetEmpAndDeptById() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Map<String, Object> emp1 = empMapper.getEmpAndDeptByIdOne(1);// 方式一
        System.out.println("***************************开始***************************" );
        System.out.println("方式一:"+emp1);
        System.out.println("***************************结束***************************" );
    }
}
  • 查询结果
    在这里插入图片描述
(b)resultMap 级联属性赋值
  • EmpMapper 接口方法
    /**
     * 根据员工id查询员工信息和员工所在部门信息
     * <p>
     * 分步查询 根据员工id查询员工信息和员工所在部门信息
     * 1、 先根据员工id查询员工信息
     * 2、 再根据员工信息中的部门id去获取对应的部门信息
     */
    Emp getEmpAndDeptByIdTwo(@Param("id") Integer id);


  • EmpMapper 映射文件
<?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.ningxia.mybatis.mapper.EmpMapper">

  <!--方式二:resultMap 级联属性赋值-->
    <select id="getEmpAndDeptByIdTwo" resultMap="empResultMapOne">
        select
        *
        from t_emp e
        left join t_dept d
        on e.did = d.did
        where e.eid = #{id}
    </select>

    <resultMap id="empResultMapOne" type="Emp">
        <!-- id 标签 用来设置主键的映射关系-->
        <id property="eid" column="eid"/>
        <!-- result 标签 用来设置普通字段的映射关系-->
        <result property="empName" column="emp_name"/>
        <result property="age" column="age"/>
        <result property="sex" column="sex"/>
        <result property="email" column="email"/>
        <result property="did" column="did"/>
        <!-- 将 t_dept 表中字段 did、dept_name的值分别
        映射到 Emp 类下的 dept对象的did、deptName属性上 -->
        <result property="dept.did" column="did"/>
        <result property="dept.deptName" column="dept_name"/>
    </resultMap>



</mapper>

  • 测试类方法
package com.ningxia.mybatis.test;

import com.ningxia.mybatis.mapper.EmpMapper;
import com.ningxia.mybatis.pojo.Emp;
import com.ningxia.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;
import java.util.Map;

public class EmpMapperTest {

    /**
     * 根据员工id查询员工信息和员工所在部门信息
     * <p>
     * 分步查询 根据员工id查询员工信息和员工所在部门信息
     * 1、 先根据员工id查询员工信息
     * 2、 再根据员工信息中的部门id去获取对应的部门信息
     */
    @Test
    public void testGetEmpAndDeptById() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp2 = empMapper.getEmpAndDeptByIdTwo(1); // 方式二
        System.out.println("***************************开始***************************" );
        System.out.println("方式二:"+ emp2);
        System.out.println("***************************结束***************************" );
    }
}


  • 查询结果
    在这里插入图片描述
(c)使用 association 标签定义关联的单个对象的封装

实体类、mapper接口方法、测试类和(b)中一样,只是映射文件中定义的 resultMap 不同

  • EmpMapper 接口方法
    /**
     * 根据员工id查询员工信息和员工所在部门信息
     * <p>
     * 分步查询 根据员工id查询员工信息和员工所在部门信息
     * 1、 先根据员工id查询员工信息
     * 2、 再根据员工信息中的部门id去获取对应的部门信息
     */
    Emp getEmpAndDeptByIdThree(@Param("id") Integer id);


  • EmpMapper 映射文件
<?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.ningxia.mybatis.mapper.EmpMapper">

   <!--方式三:使用 association 标签定义关联的单个对象的封装-->
    <select id="getEmpAndDeptByIdThree" resultMap="empResultMapTwo">
        select
        *
        from t_emp e
        left join t_dept d
        on e.did = d.did
        where e.eid = #{id}
    </select>

    <resultMap id="empResultMapTwo" type="Emp">
        <!-- id 标签 用来设置主键的映射关系-->
        <id property="eid" column="eid"/>
        <!-- result 标签 用来设置普通字段的映射关系-->
        <result property="empName" column="emp_name"/>
        <result property="age" column="age"/>
        <result property="sex" column="sex"/>
        <result property="email" column="email"/>
        <result property="did" column="did"/>
        <!--使用 association标签 把 dept 对象单独封装起来
        association
            property:指定映射到实体类的对象属性(Emp类中的 dept 属性)
            javaType:指定映射到实体对象属性的类型(Emp类中的 dept 属性的类型)

        result  映射列
            property:属性名
            column:  表中字段名
        -->
        <association property="dept" javaType="Dept">
            <!-- id 标签 用来设置主键的映射关系-->
            <id property="did" column="did"/>
            <!-- result 标签 用来设置普通字段的映射关系-->
            <result property="deptName" column="dept_name"/>
        </association>
    </resultMap>


</mapper>

  • 测试类方法
package com.ningxia.mybatis.test;

import com.ningxia.mybatis.mapper.EmpMapper;
import com.ningxia.mybatis.pojo.Emp;
import com.ningxia.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;
import java.util.Map;

public class EmpMapperTest {

    /**
     * 根据员工id查询员工信息和员工所在部门信息
     * <p>
     * 分步查询 根据员工id查询员工信息和员工所在部门信息
     * 1、 先根据员工id查询员工信息
     * 2、 再根据员工信息中的部门id去获取对应的部门信息
     */
    @Test
    public void testGetEmpAndDeptById() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp3 = empMapper.getEmpAndDeptByIdThree(1); // 方式三
        System.out.println("***************************开始***************************" );
        System.out.println("方式三:"+emp3);
        System.out.println("***************************结束***************************" );
    }
}


  • 查询结果
    在这里插入图片描述
(d)association 分段查询
  • EmpMapper 接口方法
    /**
     * 根据员工id查询员工信息和员工所在部门信息
     * <p>
     * 分步查询 根据员工id查询员工信息和员工所在部门信息
     * 1、 先根据员工id查询员工信息
     * 2、 再根据员工信息中的部门id去获取对应的部门信息
     */
    Emp getEmpAndDeptByIdFour(@Param("id") Integer id);


  • EmpMapper 映射文件
<?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.ningxia.mybatis.mapper.EmpMapper">

    <!--方式四:使用 association 分段查询
        分步查询 根据员工id查询员工信息和员工所在部门信息
        1、先根据员工id查询员工信息
        2、再根据员工信息中的部门id去获取对应的部门信息
    -->
    <select id="getEmpAndDeptByIdFour" resultMap="empInfoByStepMap">
        select * from t_emp where eid = #{id}
    </select>

    <!--定义一个 resultMap -->
    <resultMap id="empInfoByStepMap" type="Emp">
        <!-- id 标签 用来设置主键的映射关系-->
        <id property="eid" column="eid"/>
        <!-- result 标签 用来设置普通字段的映射关系-->
        <result property="empName" column="emp_name"/>
        <result property="age" column="age"/>
        <result property="sex" column="sex"/>
        <result property="email" column="email"/>
        <result property="did" column="did"/>
        <!--使用 association标签 把 dept 对象单独封装起来
            association
                property:指定映射到实体类的对象属性(Emp类中的 dept 属性)
                javaType:指定映射到实体对象属性的类型(Emp类中的 dept 属性的类型)
                column:指定表中对应的字段(即查询返回的列名,用该字段去关联查询)
                select:指定引入嵌套查询的子SQL语句的id值(即查询员工对应部门信息的sql id值 getEmpAndDeptByIdStepTwo)

            result  映射列
                property:属性名
                column:  表中字段名
        -->
        <association property="dept" javaType="Dept" column="did" select="getEmpAndDeptByIdStepTwo">
            <!-- id 标签 用来设置主键的映射关系-->
            <id property="did" column="did"/>
            <!-- result 标签 用来设置普通字段的映射关系-->
            <result property="deptName" column="dept_Name"/>
        </association>
    </resultMap>

    <select id="getEmpAndDeptByIdStepTwo" resultType="Dept">
        select * from t_dept where did = #{did}
    </select>

</mapper>

  • 测试类方法
package com.ningxia.mybatis.test;

import com.ningxia.mybatis.mapper.EmpMapper;
import com.ningxia.mybatis.pojo.Emp;
import com.ningxia.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;
import java.util.Map;

public class EmpMapperTest {

    /**
     * 根据员工id查询员工信息和员工所在部门信息
     * <p>
     * 分步查询 根据员工id查询员工信息和员工所在部门信息
     * 1、 先根据员工id查询员工信息
     * 2、 再根据员工信息中的部门id去获取对应的部门信息
     */
    @Test
    public void testGetEmpAndDeptById() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp4 = empMapper.getEmpAndDeptByIdFour(1); // 方式四
        System.out.println("***************************开始***************************" );
        System.out.println("方式四:"+emp4);
        System.out.println("***************************结束***************************" );
    }
}


  • 查询结果
    在这里插入图片描述

上述 分步查询所有SQL都是在映射文件 EmpMapper.xml中写的,也可以分开写,EmpDept的信息各自写在自己的映射文件中

  • EmpMapper 接口方法

 /**
  * 根据员工id查询员工信息和员工所在部门信息
  * <p>
  * 分步查询 根据员工id查询员工信息和员工所在部门信息
  * 1、 先根据员工id查询员工信息
  * 2、 再根据员工信息中的部门id去获取对应的部门信息
  */
Emp getEmpAndDeptByIdFive(@Param("id") Integer id);


  • EmpMapper 映射文件
<?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.ningxia.mybatis.mapper.EmpMapper">

    <!--方式五:使用 association 分段查询  分开写
        分步查询 根据员工id查询员工信息和员工所在部门信息
        1、先根据员工id查询员工信息
        2、再根据员工信息中的部门id去获取对应的部门信息
    -->
    <select id="getEmpAndDeptByIdFive" resultMap="empInfo">
        select * from t_emp where eid = #{id}
    </select>

    <!--定义一个 resultMap -->
    <resultMap id="empInfo" type="Emp">
        <!-- id 标签 用来设置主键的映射关系-->
        <id property="eid" column="eid"/>
        <!-- result 标签 用来设置普通字段的映射关系-->
        <result property="empName" column="emp_name"/>
        <result property="age" column="age"/>
        <result property="sex" column="sex"/>
        <result property="email" column="email"/>
        <result property="did" column="did"/>
        <!--使用 association标签 把 dept 对象单独封装起来
            association
                property:指定映射到实体类的对象属性(Emp类中的 dept 属性)
                javaType:指定映射到实体对象属性的类型(Emp类中的 dept 属性的类型)
                column:指定表中对应的字段(即查询返回的列名,用该字段去关联查询)
                select:指定引入嵌套查询的子SQL语句的id值(即DeptMapper.xml中分步查询第二步的sql id值 getEmpAndDeptByIdStepTwo)
        -->
        <association property="dept"
                     javaType="Dept"
                     column="did"
                     select="com.ningxia.mybatis.mapper.DeptMapper.getEmpAndDeptInfoStepTwo">
        </association>
    </resultMap>

</mapper>

  • DeptMapper 映射文件
<?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.ningxia.mybatis.mapper.DeptMapper">

    <!-- 分步查询:
     根据员工id查询员工信息和员工所在部门信息
            1、先根据员工id查询员工信息
            2、再根据员工信息中的部门id去获取对应的部门信息

    第二步:2、再根据员工信息中的部门id去获取对应的部门信息
    -->
    <select id="getEmpAndDeptInfoStepTwo" resultType="Dept">
        select * from t_dept where did = #{did}
    </select>

</mapper>

  • 测试类方法
package com.ningxia.mybatis.test;

import com.ningxia.mybatis.mapper.EmpMapper;
import com.ningxia.mybatis.pojo.Emp;
import com.ningxia.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;
import java.util.Map;

public class EmpMapperTest {

    /**
     * 根据员工id查询员工信息和员工所在部门信息
     * <p>
     * 分步查询 根据员工id查询员工信息和员工所在部门信息
     * 1、 先根据员工id查询员工信息
     * 2、 再根据员工信息中的部门id去获取对应的部门信息
     */
    @Test
    public void testGetEmpAndDeptById() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp5 = empMapper.getEmpAndDeptByIdFive(1); // 方式五
        System.out.println("***************************开始***************************");
        System.out.println("方式五:分段查询分开写" + emp5);
        System.out.println("***************************结束***************************");
    }
}


  • 测试类方法
    在这里插入图片描述
(😀)分步查询之延迟加载(按需加载)
  • mybatis-config.xml 配置文件
<settings>
    <setting name="lazyLoadingEnabled" value="true" />
    <setting name="aggressiveLazyLoading" value="false" />
</settings>

lazyLoadingEnabled开启或关闭全局延时加载功能

  • true启用延时加载。 只有在需要访问某个关联属性时,才会触发查询以加载数据
  • false(默认值)关闭延时加载。MyBatis 会在加载主对象时立即加载所有关联对象

aggressiveLazyLoading控制延时加载的策略是否激进

  • true激进延时加载模式。 一旦访问对象的任意一个延时加载的属性,会立即加载所有其他延时属性。
  • false非激进延时加载模式。 只有在明确访问某个属性时,才会触发查询来加载该属性的数据,其他延时属性不会被加载。

在这里插入图片描述

  • <association> 标签中的 fetchType 属性

fetchType属性用于定义 MyBatis 关联查询的加载策略

  • lazy延时加载(Lazy Loading)
  • eager立即加载(Eager Loading)

如果 未显式指定 fetchType,会继承全局设置 lazyLoadingEnabled 的值
如果 指定了 fetchType,局部配置会覆盖全局设置

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

测试结果:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

MyBatis 3.5.11 : 因此 aggressiveLazyLoading 默认值是 false
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

(😀)lazyLoadingEnabled 与 aggressiveLazyLoading

lazyLoadingEnabledaggressiveLazyLoading 是两个相辅相成但有不同作用的配置,它们的设计并不多余,而是用来满足不同的延迟加载场景需求。

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

<settings>
  <setting name="lazyLoadingEnabled" value="true" />
  <setting name="aggressiveLazyLoading" value="true" />
</settings>

访问代码:

Order order = orderMapper.selectById(1);
// 访问 customer 时
System.out.println(order.getCustomer().getName()); // 触发延迟加载,加载 customer 和 items。
  • 一次性加载了 customeritems,即使你只访问了 customer

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

(3)一对多关联映射

中创建所对应的集合

  • (如下案例:在实体类Dept中创建Emp对应的集合对象)

案例 : 如果关联的是一个集合
【如:查询部门信息的时候,把当前部门所有员工信息也查询出来】

  • 实体类
package com.ningxia.mybatis.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
    private Integer did;
    private String deptName;
    private List<Emp> empList; // 在 Dept 中创建 Emp 对应的集合对象
}
(a)使用 collocation 处理一对多的映射关系

<collection>标签

  • 作用:表示多个关系,就是把查询出来的结果映射成一个“列表”属性。 此处就表示 这个属性(例如 empList)是一个装着“员工 Emp”的集合
  • property="empList"指定主对象中用于存储子对象集合的属性名,此处指 Dept 类中的 empList 属性。
  • ofType="Emp"指定子对象集合的类型,此处表示集合中的每个元素都是 Emp 类型。
  • DeptMapper 接口方法
    /**
     * 获取部门及部门中所有员工信息
     */
    Dept getDeptAndEmpInfoById(@Param("id") Integer id)  ;

  • DeptMapper 映射文件
<?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.ningxia.mybatis.mapper.DeptMapper">
    <!--
       获取部门及部门中所有员工信息
        Dept getDeptAndEmpInfoById(@Param("id") Integer id)  ;
    -->
    <select id="getDeptAndEmpInfoById" resultMap="DeptAndEmpMap">
        select * from t_dept d left join t_emp e on d.did = e.did where d.did = #{id}
    </select>

    <resultMap id="DeptAndEmpMap" type="Dept">
        <!-- id 标签 用来设置主键的映射关系-->
        <id column="did" property="did"/>
        <!-- result 标签 用来设置普通字段的映射关系-->
        <result column="dept_name" property="deptName"/>

        <!--
            <collection>标签
            作用:表示多个关系,就是把查询出来的结果映射成一个“列表”属性。
            此处就表示 这个属性(例如 empList)是一个装着“员工 Emp”的集合
            property="empList":指定主对象中用于存储子对象集合的属性名,此处指 Dept 类中的 empList 属性。
            ofType="Emp":指定子对象集合的类型,此处表示集合中的每个元素都是 Emp 类型。
        -->
        <collection property="empList" ofType="Emp">
            <!-- id 标签 用来设置主键的映射关系-->
            <id column="eid" property="eid"/>
            <!-- result 标签 用来设置普通字段的映射关系-->
            <result column="emp_name" property="empName"/>
            <result column="age" property="age"/>
            <result column="sex" property="sex"/>
            <result column="email" property="email"/>
            <result column="did" property="did"/>
        </collection>
    </resultMap>

</mapper>

  • 测试类方法
package com.ningxia.mybatis.test;

import com.ningxia.mybatis.mapper.DeptMapper;
import com.ningxia.mybatis.pojo.Dept;
import com.ningxia.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class DeptMapperTest {

    /**
     * 获取部门及部门中所有员工信息
     */
    @Test
    public void testGetDeptAndEmpInfoById() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = deptMapper.getDeptAndEmpInfoById(3);
        System.out.println(dept);
    }
}

  • 查询结果
    在这里插入图片描述
(b)使用 collocation 分步查询

下面示例中,分步查询都写在一块了,也可以分开写,分开写参考association 分段查询中分开写的示例,此处不在赘述


<collection>标签:

  • 作用:表示多个关系,就是把查询出来的结果映射成一个“列表”属性。
  • property :指定主对象中用于存储子对象集合的属性名
  • ofType:指定子对象集合的类型
  • column:指定表中对应的字段(即查询返回的列名,用该字段去关联查询),可以使用 column"{参数名1=列名1, 参数名2=列名2}" 的形式传递多列数据
  • select:指定引入嵌套查询的子SQL语句的id
  • fetchType="lazy|eager" : 延迟加载|立即加载;不显示写出来默认继承全局配置文件中的 lazyLoadingEnabled
  • DeptMapper 接口方法
    /**
     * 获取部门及部门中所有员工信息
     * 分步查询
     */
    Dept getDeptAndEmpInfoByStep(@Param("id") Integer id)  ;

  • DeptMapper 映射文件
<?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.ningxia.mybatis.mapper.DeptMapper">
    <!--
       获取部门及部门中所有员工信息  分步查询
        Dept getDeptAndEmpInfoByStep(@Param("id") Integer id)  ;
    -->
    <select id="getDeptAndEmpInfoByStep" resultMap="DeptAndEmpByStepMap">
        select * from t_dept where did = #{id}
    </select>

    <resultMap id="DeptAndEmpByStepMap" type="Dept">
        <!-- id 标签 用来设置主键的映射关系-->
        <id column="did" property="did"/>
        <!-- result 标签 用来设置普通字段的映射关系-->
        <result column="dept_name" property="deptName"/>
        <!--
            <collection>标签
            作用:表示多个关系,就是把查询出来的结果映射成一个“列表”属性。
            此处就表示 这个属性(例如 empList)是一个装着“员工 Emp”的集合
            property="empList":指定主对象中用于存储子对象集合的属性名,此处指 Dept 类中的 empList 属性。
            ofType="Emp":指定子对象集合的类型,此处表示集合中的每个元素都是 Emp 类型。
            column:指定表中对应的字段(即查询返回的列名,用该字段去关联查询)
            select:指定引入嵌套查询的子SQL语句的id值(即查询员工对应部门信息的 sql id值 getDeptAndEmpInfoByStepTwo
            fetchType="lazy|eager" : 延迟加载|立即加载;不显示写出来默认继承全局配置文件中的 lazyLoadingEnabled 值
        -->
        <collection property="empList"
                    ofType="Emp"
                    column="did"
                    select="getDeptAndEmpInfoByStepTwo"
                    fetchType="lazy"
        >
        </collection>
    </resultMap>

    <!--分步查询第二步:根据did查询员工信息-->
    <select id="getDeptAndEmpInfoByStepTwo" resultType="Emp">
        select * from t_emp where did = #{id}
    </select>

</mapper>

  • 测试类方法
package com.ningxia.mybatis.test;

import com.ningxia.mybatis.mapper.DeptMapper;
import com.ningxia.mybatis.pojo.Dept;
import com.ningxia.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class DeptMapperTest {

    /**
     * 获取部门及部门中所有员工信息 分步查询
     */
    @Test
    public void testGetDeptAndEmpInfoByStep() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = deptMapper.getDeptAndEmpInfoByStep(3);
        System.out.println(dept.getDeptName());
    }
}

  • 查询结果
    在这里插入图片描述
    在这里插入图片描述

五、MyBatis 基础功能之动态 SQL

MyBatis动态 SQL 是其核心功能之一,用于根据条件动态生成 SQL 语句。

  • 动态SQL标签:

if

  • 根据标签中test属性所对应的表达式决定标签中的内容是否拼接到SQL中;
    <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp where
        <if test="empName != null and empName != ''">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="sex != null and sex != ''">
            and sex = #{sex}
        </if>
        <if test="email != null and email != ''">
            and email = #{email}
        </if>
    </select>
  • 存在问题:假如第一个条件为空,会造成 where 后面直接拼接 andSQL 语句错误导致查询失败 在这里插入图片描述

  • 解决办法:

  • where 后面拼接 1=1 这样的类似语句

在这里插入图片描述

  • 使用 <where>标签
    在这里插入图片描述

where

  • where 标签中有内容时,会自动生成 where 关键字,并且将内容前多余的 andor 去掉;
  • where 标签中没有内容时,此时 where标签没有任何效果;

注意:where 标签 不能 将内容后面多余的 andor 去掉;

    <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <where>
            <if test="empName != null and empName != ''">
                 and emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="sex != null and sex != ''">
                and sex = #{sex}
            </if>
            <if test="email != null and email != ''">
                and email = #{email}
            </if>
        </where>
    </select>
  • 存在问题where 标签 不能 将内容后面多余的 andor 去掉;在这里插入图片描述
  • 解决办法:使用<trim>标签

trim

当标签中有内容时:

  • prefix :前缀,给拼串后的整个字符串加一个前缀
  • prefixOverrides :前缀覆盖,去掉整个字符串前面多余的字符串
  • suffix :后缀,给拼串后的整个字符串加一个后缀
  • suffixOverrides :后缀覆盖,去掉整个字符串后面多余的字符

当标签中没有内容时,trim标签也没有任何效果

<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp
    <trim prefix="where" suffixOverrides="and|or">
        <if test="empName != null and empName != ''">
            emp_name = #{empName} and
        </if>
        <if test="age != null and age != ''">
            age = #{age} and
        </if>
        <if test="sex != null and sex != ''">
            sex = #{sex} and
        </if>
        <if test="email != null and email != ''">
            email = #{email}
        </if>
    </trim>
</select>
******************************
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp
    <trim prefix="where" prefixOverrides="and|or">
        <if test="empName != null and empName != ''">
            and emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="sex != null and sex != ''">
            or sex = #{sex}
        </if>
        <if test="email != null and email != ''">
            and email = #{email}
        </if>
    </trim>
</select>

choose…when…otherwise

  • choose标签 (when,otherwise): 分支选择,类似 if...else if...else 或带了breakswtich-case只会进入其中一个分支
  • when 至少有一个,otherwise最多有一个;
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp
    <where>
        <choose>
            <when test="empName != null and empName != ''">
                emp_name = #{empName}
            </when>
            <when test="age != null and age != ''">
                age = #{age}
            </when>
            <when test="sex != null and sex != ''">
                sex = #{sex}
            </when>
            <otherwise>
                sex = '女'
            </otherwise>
        </choose>
    </where>
</select>

在这里插入图片描述

foreach

  • collection: 设置需要循环的数组或集合
  • item: 表示数组或集合中的每一个对象
  • separator(可选) 循环体之间的分隔符
  • open(可选)foreach标签所循环的所有内容的开始符
  • close(可选)foreach标签所循环的所有内容的结束符
  • index(可选) 表示当前遍历的索引。在 <foreach> 标签体中,你可以使用 #{index} 来引用当前遍历到的索引;
  • 遍历 list 的时候,index就是索引,item就是当前值;
  • 遍历 map的时候,index表示的就是mapkeyitem就是map的值
    在这里插入图片描述
  • DynamicMapper 接口方法
    /**
     * 查询: 传递参数为一个数组
     */
    List<Emp> getEmpByArray(@Param("eids") Integer[] eids);

    /**
     * 通过list集合实现批量添加员工
     */
    Integer insertMoreEmpByList(@Param("empList") List<Emp> empList);

    /**
     * 通过list集合实现批量删除员工
     */
    Integer deleteMoreEmpByList(@Param("eids")  Integer[] eids);


  • DynamicMapper 映射文件
<?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.ningxia.mybatis.mapper.DynamicMapper">
    <!-- 多条件查询
        List<Emp> getEmpByCondition(Emp emp)

       1、if标签
        <select id="getEmpByCondition" resultType="Emp">
            select * from t_emp where 1 = 1
            <if test="empName != null and empName != ''">
                emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="sex != null and sex != ''">
                and sex = #{sex}
            </if>
            <if test="email != null and email != ''">
                and email = #{email}
            </if>
        </select>

       2、where 标签
        <select id="getEmpByCondition" resultType="Emp">
            select * from t_emp
            <where>
                <if test="empName != null and empName != ''">
                    emp_name = #{empName}
                </if>
                <if test="age != null and age != ''">
                    and age = #{age}
                </if>
                <if test="sex != null and sex != ''">
                    and sex = #{sex}
                </if>
                <if test="email != null and email != ''">
                    and email = #{email}
                </if>
            </where>
        </select>

       3、trim 标签
        <select id="getEmpByCondition" resultType="Emp">
            select * from t_emp
            <trim prefix="where" suffixOverrides="and|or">
                <if test="empName != null and empName != ''">
                    emp_name = #{empName} and
                </if>
                <if test="age != null and age != ''">
                    age = #{age} and
                </if>
                <if test="sex != null and sex != ''">
                    sex = #{sex} and
                </if>
                <if test="email != null and email != ''">
                    email = #{email}
                </if>
            </trim>
        </select>
        ******************************
        <select id="getEmpByCondition" resultType="Emp">
            select * from t_emp
            <trim prefix="where" prefixOverrides="and|or">
                <if test="empName != null and empName != ''">
                    and emp_name = #{empName}
                </if>
                <if test="age != null and age != ''">
                    and age = #{age}
                </if>
                <if test="sex != null and sex != ''">
                    or sex = #{sex}
                </if>
                <if test="email != null and email != ''">
                    and email = #{email}
                </if>
            </trim>
        </select>

       4、choose…when…otherwise 标签
           <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <where>
            <choose>
                <when test="empName != null and empName != ''">
                    emp_name = #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <when test="sex != null and sex != ''">
                    sex = #{sex}
                </when>
                <otherwise>
                    sex = '女'
                </otherwise>
            </choose>
        </where>
    -->
    <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <where>
            <choose>
                <when test="empName != null and empName != ''">
                    emp_name = #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <when test="sex != null and sex != ''">
                    sex = #{sex}
                </when>
                <otherwise>
                    sex = '女'
                </otherwise>
            </choose>
        </where>
    </select>


    <!--  查询: 传递参数为一个数组
        List<Emp>  getEmpByArray(@Param("eids") Integer[] eids)

        collection: 设置需要循环的数组或集合;
        item: 表示数组或集合中的每一个对象;
        separator:(可选) 循环体之间的分隔符;
        open: (可选)foreach标签所循环的所有内容的开始符;
        close: (可选)foreach标签所循环的所有内容的结束符;
        index:(可选)表示当前遍历的索引。在 <foreach> 标签体中,你可以使用 #{index} 来引用当前遍历到的索引;
            遍历 list 的时候,index就是索引,item就是当前值;
            遍历 map的时候,index表示的就是map的key,item就是map的值

    -->
    <select id="getEmpByArray" resultType="Emp">
        select * from t_emp where eid in
        <foreach collection="eids" item="eid" separator="," open="(" close=")">
            #{eid}
        </foreach>
    </select>


    <!--  通过list集合实现批量添加员工
        Integer insertMoreEmpByList(List<Emp> empList);
    -->
    <insert id="insertMoreEmpByList">
        insert into t_emp values
        <foreach collection="empList" item="emp" separator=",">
            (null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},null)
        </foreach>
    </insert>


    <!--  通过list集合实现批量删除员工
    Integer deleteMoreEmpByList(@Param("eids")  Integer[] eids);
    -->
    <delete id="deleteMoreEmpByList">
        delete from t_emp where eid in
        <foreach collection="eids" item="eid" separator="," open="(" close=")">
            #{eid}
        </foreach>
    </delete>
</mapper>

  • 测试类方法
package com.ningxia.mybatis.test;

import com.ningxia.mybatis.mapper.DynamicMapper;
import com.ningxia.mybatis.pojo.Emp;
import com.ningxia.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;

public class DynamicMapperTest {

    /**
     * 通过list集合实现批量删除员工
     */
    @Test
    public void testDeleteMoreEmpByList() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        DynamicMapper dynamicMapper = sqlSession.getMapper(DynamicMapper.class);
        Integer result = dynamicMapper.deleteMoreEmpByList(new Integer[]{28, 29, 30, 31, 32, 33, 34});
        System.out.println("成功删除员工:" + result + " 条");
    }

    /**
     * 通过list集合实现批量添加员工
     */
    @Test
    public void testInsertMoreEmpByList() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        DynamicMapper dynamicMapper = sqlSession.getMapper(DynamicMapper.class);
        Emp emp0 = new Emp(null, "小明0", 23, '男', "231568@qq.com", null, null);
        Emp emp1 = new Emp(null, "小明1", 23, '男', "231568@qq.com", null, null);
        Emp emp2 = new Emp(null, "小明2", 23, '男', "231568@qq.com", null, null);
        Emp emp3 = new Emp(null, "小明3", 23, '男', "231568@qq.com", null, null);
        Emp emp4 = new Emp(null, "小明4", 23, '男', "231568@qq.com", null, null);
        Emp emp5 = new Emp(null, "小明5", 23, '男', "231568@qq.com", null, null);
        Emp emp6 = new Emp(null, "小明6", 23, '男', "231568@qq.com", null, null);
        List<Emp> empList = Arrays.asList(emp0, emp1, emp2, emp3, emp4, emp5, emp6);
        Integer result = dynamicMapper.insertMoreEmpByList(empList);
        System.out.println("成功新增员工:" + result + " 条");
    }


    /**
     * 查询: 传递参数为一个数组
     */
    @Test
    public void testGetEmpByArray() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        DynamicMapper dynamicMapper = sqlSession.getMapper(DynamicMapper.class);
        List<Emp> empList = dynamicMapper.getEmpByArray(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9});
        empList.forEach(System.out::println);
    }


    /**
     * 多条件查询
     */
    @Test
    public void testGetEmpByCondition() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        DynamicMapper dynamicMapper = sqlSession.getMapper(DynamicMapper.class);
        List<Emp> empList = dynamicMapper.getEmpByCondition(new Emp(null, "Bob", 66, '男', "bob@example.com", null, null));
//        List<Emp> empList = dynamicMapper.getEmpByCondition(new Emp(null, "Bob",null , null, "", null, null));
//        List<Emp> empList = dynamicMapper.getEmpByCondition(new Emp(null, "Kevin", null, '男', "kevin@example.com", null, null));
//        List<Emp> empList = dynamicMapper.getEmpByCondition(new Emp(null, "", null, null, "", null, null));
        empList.forEach(System.out::println);
    }

}


  • 测试结果
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

sql

  • 抽取重复可用的SQL片段,可以与<where>、<trim>等动态SQL标签组合使用,实现更复杂的逻辑,必须在mapper文件中批量声明,不能在其他 SQL 标签中调用(如<select>
  • mapper文件中 定义 SQL 片段,引用 SQL 片段
<!-- 定义 SQL 片段 
	id:为 SQL 片段指定唯一标识符。
-->
<sql id="userColumns">
    id, name, age, email
</sql>



<!-- 引用 SQL 片段
	refid:指定要引用的SQL片段的ID。
 -->
<select id="findUsers" resultType="User">
    SELECT
    <include refid="userColumns" />
    FROM users
</select>

  • 生成的 SQL 片段
SELECT id, name, age, email FROM users;

set

  • <set>MyBatis动态SQL的标签,集中于动态生成UPDATE语句的SET部分,简化了字段更新的逻辑,避免手动拼接内容时产生多余的重要问题。
  • 示例代码

动态更新字段

<update id="updateUser" parameterType="map">
    UPDATE users
    <set>
        <if test="name != null">
            name = #{name},
        </if>
        <if test="age != null">
            age = #{age},
        </if>
        <if test="email != null">
            email = #{email},
        </if>
    </set>
    WHERE id = #{id}
</update>
  • 传入参数
{
  "id": 1,
  "name": "John",
  "email": "john@example.com"
}

  • 生成 SQL
 <!--<set>自动去掉了email后多余的逗号-->

UPDATE users
SET name = 'John',
    email = 'john@example.com'
WHERE id = 1

条件更新:如果只更新部分字段,可以根据null判断条件动态生成需要的内容。

<update id="updateUserSelective" parameterType="User">
    UPDATE users
    <set>
        <if test="name != null">
            name = #{name},
        </if>
        <if test="age != null">
            age = #{age},
        </if>
        <if test="email != null">
            email = #{email},
        </if>
    </set>
    WHERE id = #{id}
</update>

  • 传入参数
{
  "id": 2,
  "age": 25
}
  • 生成 SQL
UPDATE users SET age = 25 WHERE id = 2

配合动态字段的更新

<update id="updateDynamic">
    UPDATE users
    <set>
        <foreach collection="fields" index="key" item="value" separator=",">
            ${key} = #{value}
        </foreach>
    </set>
    WHERE id = #{id}
</update>

  • 传入参数
{
  "id": 3,
  "fields": {
    "name": "Alice",
    "email": "alice@example.com"
  }
}

  • 生成 SQL
UPDATE users
SET name = 'Alice',
    email = 'alice@example.com'
WHERE id = 3

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/927012.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【热门主题】000069 服务器虚拟化:开启高效资源管理新时代

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

day22:lamp项目部署

一&#xff0c;lamp概述 lamp概述 LAMP 是一组开源软件的缩写&#xff0c;用于搭建动态网站或Web应用程序的基础环境。LAMP 代表了四个主要的组成部分&#xff1a; Linux&#xff1a;操作系统&#xff0c;LAMP 环境的基础。通常使用的是 Linux 发行版&#xff0c;如 CentOS、…

通俗易懂:序列标注与命名实体识别(NER)概述及标注方法解析

目录 一、序列标注&#xff08;Sequence Tagging&#xff09;二、命名实体识别&#xff08;Named Entity Recognition&#xff0c;NER&#xff09;**命名实体识别的作用****命名实体识别的常见实体类别** &#xff1a; 三、标签类型四、序列标注的三种常见方法1. **BIO&#xf…

01-Ubuntu24.04LTS上安装PGSQL

目录 一、准备工作 1.1、系统要求 1.2 、更新 Ubuntu 系统 1.3 、安装依赖 1.4 、添加 PostgreSQL 16 软件源 二、安装 PostgreSQL 16 数据库 三、管理 PostgreSQL 服务 四、PostgreSQL 管理操作 4.1 、访问 Postgres 超级用户账户 4.2 、创建数据库并设置管理权限 4…

利用阿里云镜像仓库和 Github Action 同步镜像

利用阿里云镜像仓库和 Github Action 同步镜像 由于某些未知原因,国内无法直接从 DockerHub 拉取镜像,在不使用 VPN 等违法工具的情况下,可以利用 GitHub 的 Action 流水线功能,将镜像推送到阿里云的个人镜像仓库中。 这种方式相较于其他方式虽然相对麻烦,但好在免费,且实…

iOS与Windows间传文件

想用数据线从 windows 手提电脑传文件入 iPhone&#xff0c;有点迂回。 参考 [1]&#xff0c;要在 windows 装 Apple Devices。装完、打开、插线之后会检测到手机&#xff0c;界面&#xff1a; 点左侧栏「文件」&#xff0c;不是就直接可以传&#xff0c;而是要通过某个应用传…

如何使用Python解析从淘宝API接口获取到的JSON数据?

基本的 JSON 解析 当从淘宝 API 接口获取到数据后&#xff08;假设数据存储在变量response_data中&#xff09;&#xff0c;首先要判断数据类型是否为 JSON。如果是&#xff0c;就可以使用 Python 内置的json模块进行解析。示例代码如下&#xff1a; import json # 假设respon…

Cesium K-means自动聚合点的原理

Cesium K-means自动聚合点的原理 Cesium 是一个开源的 JavaScript 库&#xff0c;用于在 Web 环境中创建 3D 地球和地图应用。它能够处理地理空间数据&#xff0c;并允许开发者对大规模的地理数据进行可视化展示。在一些应用中&#xff0c;尤其是当处理大量地理坐标点时&#…

入门数据结构JAVADS——如何构建一棵简单二叉排序树

目录 前言 什么是二叉排序树 二叉排序树的特点 二叉排序树示意图 构建二叉排序树 插入元素 搜索元素 删除元素 完整代码 结尾 前言 在整个十一月,笔者因为一些原因停笔了,但马上迈入12月进而进入2025年,笔者决定不再偷懒了,继续更新以促进学习的积极性.闲话说到这,今天…

【深度学习】四大图像分类网络之AlexNet

AlexNet是由Alex Krizhevsky、Ilya Sutskever&#xff08;均为Hinton的学生&#xff09;和Geoffrey Hinton&#xff08;被誉为”人工智能教父“&#xff0c;首先将反向传播用于多层神经网络&#xff09;在2012年ImageNet图像分类竞赛中提出的一种经典的卷积神经网络。AlexNet在…

基于 Python、OpenCV 和 PyQt5 的人脸识别上课打卡系统

大家好&#xff0c;我是Java徐师兄&#xff0c;今天为大家带来的是基于 Python、OpenCV 和 PyQt5 的人脸识别上课签到系统。该系统采用 Python 语言开发&#xff0c;开发过程中采用了OpenCV框架&#xff0c;Sqlite db 作为数据库&#xff0c;系统功能完善 &#xff0c;实用性强…

DevOps工程技术价值流:Jenkins驱动的持续集成与交付实践

一、Jenkins系统概述 Jenkins&#xff1a;开源CI/CD引擎的佼佼者 Jenkins&#xff0c;作为一款基于Java的开源持续集成&#xff08;CI&#xff09;与持续交付&#xff08;CD&#xff09;系统&#xff0c;凭借其强大的插件生态系统&#xff0c;成为DevOps实践中不可或缺的核心…

亚马逊开发视频人工智能模型,The Information 报道

根据《The Information》周三的报道&#xff0c;电子商务巨头亚马逊&#xff08;AMZN&#xff09;已开发出一种新的生成式人工智能&#xff08;AI&#xff09;&#xff0c;不仅能处理文本&#xff0c;还能处理图片和视频&#xff0c;从而减少对人工智能初创公司Anthropic的依赖…

mac下安装Ollama + Open WebUI + Llama3.1

本文介绍mac下安装Ollama Open WebUI Llama3.1 8b具体步骤。 目录 推荐配置Ollama Open WebUI Llama3.1简介安装Ollama安装Open WebUI 推荐配置 m1以上芯片&#xff0c;16g内存&#xff0c;20g以上硬盘空间 Ollama Open WebUI Llama3.1简介 Ollama: 下载&#xff0c;管理…

Swift实现高效链表排序:一步步解读

文章目录 前言摘要问题描述题解解题思路Swift 实现代码代码分析示例测试与结果 时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗留问题&#xff0c;最近有时间将以往遗留问题一一完善。 148. 排序链表 不积跬步&#xff0c;无以至千里&#xff1b;不积小流…

小程序-基于java+SpringBoot+Vue的校园快递平台系统设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

网页开发的http基础知识

请求方式-GET&#xff1a;请求参数在请求行中&#xff0c;没有请求体&#xff0c;如&#xff1a;/brand/findAll?nameoPPo&status1。GET请求大小在浏览器中是有限制的请求方式-POST&#xff1a;请求参数在请求体中&#xff0c;POST请求大小是没有限制的 HTTP请求&#xf…

Qt自定义 Qt Designer 插件

创建 Qt Designer 插件项目 Qt 提供两种设计插件的 API&#xff0c;可以用于扩展 Qt 的功能。高级 API 用于设计插件以扩展 Qt 的功能&#xff0c;例如定制数据库驱动、图像格式、文本编码、定制样式等。Qt Designer 里大量采用了插件&#xff0c;点击 Qt Creator 的“Help”-…

周鸿祎再次“创业”,盯上百度

周鸿祎特地拍了部短剧来推广的新产品&#xff0c;终于上线了。 11月27日晚间&#xff0c;360正式发布多模态内容创作引擎“纳米搜索”。 作为当前AI应用最红的赛道之一&#xff0c;AI搜索已经有腾讯、秘塔、商汤、抖音等公司入局。传统搜索老大百度也在发力。竞争不妨碍有搜索…

003 MATLAB基础计算

01 方程组的求解 多项式及其运算 多项式在MATLAB中以向量形式存储。 即n次多项式用一个长度为n1的系数向量来表示&#xff0c;且按降幂&#xff0c;缺少的幂次对应的向量元素为0。 多项式的运算主要包括多项式的四则运算、求导、求值和求根运算 多项式的四则运算&#xff1a…