目录
一.动态SQL
1.1标签
1.2 标签
1.3标签
1.4标签
1.5标签
1.6标签
mybatis总结:
二.Mybatis-Puls
2.1准备工作
2.2CRUD单元测试
2.2.1创建UserInfo实体类
2.2.2编写Mapper接⼝类
2.2.3 测试类
2.3 常见注解
2.3.1@TableName
2.3.2@TableField
2.4打印日志
2.5条件构造器
2.5.1QueryWrapper
查询操作
更新
删除
2.5.2UpdateWrapper
2.5.3LambdaQueryWrapper
2.5.4 LambdaUpdateWrapper
2.6⾃定义SQL
示例1:
示例二 XML的⽅式完成
示例三:使用注解的方式
MyBatis-Plus总结:
可以先回顾一下初识Mybatis
一.动态SQL
动态 SQL 是Mybatis的强⼤特性之⼀,能够完成不同条件下不同的 sql 拼接可以参考官方文档:MyBatis动态sql
熟悉使用各种标签
1.1<if>标签
在注册信息的时候,可能会遇到这种问题,如图:
 
注册分为两种字段:必填字段和⾮必填字段,那如果在添加⽤⼾的时候有不确定的字段传⼊,程序应 该如何实现呢?这个时候就需要使⽤动态标签 来判断了,⽐如添加的时候性别 gender 为⾮必填字段,具体实现如 下
Mapper接⼝定义:
@Mapper
public interface UserInfoXmlMapper {
    Integer insertUserByCondition(UserInfo userInfo);
} 
Mapper.xml实现:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatis.mapper.UserInfoXmlMapper">
    <insert id="insertUserByCondition">
         INSERT INTO user_info(
         username,
         `password`,
         age,
         <if test="gender != null">
             gender,
         </if>
         phone)
         VALUES (
         #{username},
         #{age},
         <if test="gender != null">
             #{gender},
         </if>
         #{phone})
    </insert>
</mapper> 
 
注解⽅式(不推荐)
@Insert("<script>" +
     "INSERT INTO userinfo (username,`password`,age," +
     "<if test='gender!=null'>gender,</if>" +
     "phone)" +
     "VALUES(#{username},#{age}," +
     "<if test='gender!=null'>#{gender},</if>" +
     "#{phone})"+
     "</script>")
Integer insertUserByCondition(UserInfo userInfo); 
注意 test 中的 gender,是传⼊对象中的属性,不是数据库字段问: 可不可以不进⾏判断, 直接把字段设置为null呢?答: 不可以, 这种情况下, 如果gender字段有默认值, 就会设置为默认值
测试代码:
@Test
    void insertUserByCondition() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("cuihua");
        userInfo.setPassword("cuihua");
        userInfo.setAge(23);
        userInfo.setPhone("11111111111");
        System.out.println(userInfoXmlMapper.insertUserByCondition(userInfo));
    } 
测试结果:

1.2<trim> 标签
- prefix:表⽰整个语句块,以prefix的值作为前缀
 - suffix:表⽰整个语句块,以suffix的值作为后缀
 - prefixOverrides:表⽰整个语句块要去除掉的前缀
 - suffixOverrides:表⽰整个语句块要去除掉的后缀
 
调整后的.XML代码:
<insert id="insertUserByCondition">
        INSERT INTO user_info
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username !=null">
                username,
            </if>
            <if test="password !=null">
                `password`,
            </if>
            <if test="age != null">
                age,
            </if>
            <if test="gender != null">
                gender,
            </if>
            <if test="phone != null">
                phone,
            </if>
        </trim>
        VALUES
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username !=null">
                #{username},
            </if>
            <if test="password !=null">
                #{password},
            </if>
            <if test="age != null">
                #{age},
            </if>
            <if test="gender != null">
                #{gender},
            </if>
            <if test="phone != null">
                #{phone}
            </if>
        </trim>
    </insert> 
 @Insert("<script>" +
            "INSERT INTO user_info " +
            "<trim prefix='(' suffix=')' suffixOverrides=','>" +
            "<if test='username!=null'>username,</if>" +
            "<if test='password!=null'>password,</if>" +
            "<if test='age!=null'>age,</if>" +
            "<if test='gender!=null'>gender,</if>" +
            "<if test='phone!=null'>phone,</if>" +
            "</trim>" +
            "VALUES " +
            "<trim prefix='(' suffix=')' suffixOverrides=','>" +
            "<if test='username!=null'>#{username},</if>" +
            "<if test='password!=null'>#{password},</if>" +
            "<if test='age!=null'>#{age},</if>" +
            "<if test='gender!=null'>#{gender},</if>" +
            "<if test='phone!=null'>#{phone}</if>" +
            "</trim>"+
            "</script>")
    Integer insertUserByCondition1(UserInfo userInfo); 
在以上 sql 动态解析时,会将第⼀个 部分做如下处理:
- 基于 prefix 配置,开始部分加上 (
 - 基于 suffix 配置,结束部分加上 )
 - 多个 组织的语句都以 , 结尾,在最后拼接好的字符串还会以 , 结尾,会基于 suffixOverrides 配置去掉最后⼀个 ,
 - 注意 <if test="username !=null"> 中的 username 是传⼊对象的属性
 
1.3<where>标签
需求: 传⼊的⽤⼾对象,根据属性做where条件查询,⽤⼾对象中属性不为 null 的,都为查询条件. 例如 username 为 "a",则查询条件为 where username="a"
@Mapper
public interface UserInfoXmlMapper {
    List<UserInfo> selecetByCondition(UserInfo userInfo);
} 
 .XML代码实现:
  <select id="selecetByCondition" resultType="com.example.mybatis.model.UserInfo">
        select * from user_info
        <where>
            <if test="username != null">
                username = #{username}
            </if>
            <if test="password != null">
                password = #{password}
            </if>
        </where>
    </select> 
 <where> 只会在⼦元素有内容的情况下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的AND或 OR
测试代码:
查询条件我只写了一个,可以写多个的
 @Test
    void selecetByCondition() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("wangwu");
        System.out.println(userInfoXmlMapper.selecetByCondition(userInfo));
    } 
测试结果:

1.4<set>标签
需求: 根据传⼊的⽤⼾对象属性来更新⽤⼾数据,可以使⽤标签来指定动态内容接⼝定义: 根据传⼊的⽤⼾ id 属性,修改其他不为 null 的属性@Mapper public interface UserInfoXmlMapper { Integer updateByCondition(UserInfo userInfo); }.XML代码实现:
<update id="updateByCondition"> update user_info <set> <if test="username != null" > username = #{username}, </if> <if test="password != null" > password = #{password}, </if> <if test="age != null" > age = #{age} </if> </set> where id = #{id} </update>测试代码:
目的把ID为 '1' 的名字改为 "tietui" ,并打印
@Test void updateByCondition() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("tietui"); userInfo.setId(1); System.out.println(userInfoXmlMapper.updateByCondition(userInfo)); }测试结果:
<set> :动态的在SQL语句中插⼊set关键字,并会删掉额外的逗号. (⽤于update语句中)
1.5<foreach>标签
- collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
 - item:遍历时的对象
 - open:语句块开头的字符串
 - close:语句块结束的字符串
 - separator:每次遍历之间间隔的字符串
 
需求目的: 根据多个userid, 删除⽤⼾数据
接口方法实现:
@Mapper
public interface UserInfoXmlMapper {
    Integer delete(List<Integer> list);
} 
.XML代码实现:
    <delete id="delete">
        delete from user_info
        where id in
        <foreach collection="list" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete> 
测试代码:
    @Test
    void Delete() {
        List<Integer> list =new ArrayList<>();
        list.add(5);
        list.add(8);
        System.out.println(userInfoXmlMapper.delete(list));
    } 
测试结果:
 
1.6<include>标签
就是直接对需要的代码进⾏抽取,将其通过 <sql> 标签封装到⼀个SQL⽚段,然后再通过 <include> 标签进⾏引⽤
- <sql> :定义可重⽤的SQL⽚段
 - <include> :通过属性refid,指定包含的SQL⽚段
 
<sql id="allColumn">
 id, username, age, gender, phone, delete_flag, create_time, update_time
</sql> 
  <select id="queryById" resultType="com.example.mybatis.model.UserInfo">
        select
        <include refid="allColumn"></include>
        from userinfo where id= #{id}
 </select> 
  mybatis总结:
- 学习了MyBatis动态SQL的⼀些标签使⽤. <if>标签中, 使⽤的是Java对象的属性, ⽽⾮数据库字段.
 - 动态SQL的实现, 注解和xml的实现⽅式相似, 区别是注解⽅式需要添加 <script></script> .
 - 但是使⽤注解的⽅式时, Idea不会进⾏格式检测, 容易出错, 建议使⽤xml的⽅式
 
二.Mybatis-Puls
MyBatis-Plus(简称 MP) 是⼀个 MyBatis 的增强⼯具, 在 MyBatis 的基础上只做增强不做改变, 为简化开 发. 提⾼效率⽽⽣
特性:
- 润物⽆声: 只做增强不做改变,引⼊它不会对现有⼯程产⽣影响,如丝般顺滑.
 - 效率⾄上: 只需简单配置,即可快速进⾏单表 CRUD 操作,从⽽节省⼤量时间.
 - 丰富功能: 代码⽣成、⾃动分⻚、逻辑删除、⾃动填充、拦截器等功能⼀应俱全.
 - ⼴泛认可: 连续 5 年获得开源中国年度最佳开源项⽬殊荣,Github 累计 16K Star.
 
⽀持数据库:
PostgreSQL, MySQL, MariaDB, Oracle, SQL Server, OceanBase, H2, DB2...(任何能使⽤ MyBatis 进⾏增删改查,并且⽀持标准 SQL 的数据库应该都在 MyBatis-Plus 的⽀持范围内)
官方网址:MyBatis-Puls 为简化开发而生
Mybatis-Plus操作数据库的步骤:
- 准备⼯作(数据准备, 项⽬准备, 引⼊依赖, 配置数据库连接信息)
 - 编码(数据库表对应的实体类, 以及数据操作的Mapper⽂件)
 - 测试
 
2.1准备工作
创建数据库 ➡️ 创建表(例如用户表) ➡️ 创建对应的实体类User
与Mybatis一样:
- 创建springboot项目
 - 添加MyBatis-Plus和MySQL依赖, 配置数据库连接信息
 
添加 MyBatis-Plusy依赖
    <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.9</version>
    </dependency> 
添加 MySQL依赖
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency> 
.yml文件配置:
# 数据库连接配置
spring:
  datasource:
    #数据库连接的url
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    #连接数据库的⽤⼾名
    username: root
    #连接数据库的⽤⼾名
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
  # 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
    mapper-locations: classpath:mybatis/**Mapper.xml
  # 配置打印 MyBatis日志
    configuration:
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      map-underscore-to-camel-case: true #配置驼峰⾃动转换
 
2.2CRUD单元测试
2.2.1创建UserInfo实体类
实体类的属性名与表中的字段名一一对应
package com.example.mybatisplus.mode;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
@TableName("user_info")
public class UserInfo {
    @TableId
    private Integer id;
    @TableField("username")
    private String username ;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}
 
2.2.2编写Mapper接⼝类
MybatisPlus提供了⼀个基础的 BaseMapper 接⼝,已经实现了单表的CRUD, 我们⾃定义的
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
} 
也可以在启动类上添加 @MapperScan , 扫描Mapper⽂件夹, ⼆选⼀即可.
2.2.3 测试类
在创建出来的SpringBoot⼯程中,在src下的test⽬录下,已经⾃动帮我们创建好了测试类 ,我们可以 直接使⽤这个测试类来进⾏测试
测试基本的CRUD功能 :
package com.example.mybatisplus;
import com.example.mybatisplus.mapper.UserInfoMapper;
import com.example.mybatisplus.mode.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class MybatisPlusApplicationTests {
    @Autowired
    UserInfoMapper userInfoMapper;
    @Test
    void contextLoads() {
        System.out.println(userInfoMapper.selectById(1));
    }
    @Test
    void testInsert() {
        UserInfo user = new UserInfo();
        user.setUsername("bite");
        user.setPassword("123456");
        user.setAge(11);
        user.setGender(0);
        user.setPhone("18610001234");
        userInfoMapper.insert(user);
    }
    @Test
    void testSelectById() {
        UserInfo user = userInfoMapper.selectById(1L);
        System.out.println("user: " + user);
    }
    @Test
    void testSelectByIds() {
        List<UserInfo> users = userInfoMapper.selectBatchIds(List.of(1L, 2L, 3L,
                4L));
        users.forEach(System.out::println);
    }
    @Test
    void testUpdateById() {
        UserInfo user = new UserInfo();
        user.setId(1);
        user.setPassword("4444444");
        userInfoMapper.updateById(user);
    }
} 
2.3 常见注解
在上⾯的程序中, MyBatis是如何知道, 我们要操作的是哪张表, 表⾥有哪些字段呢?
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
} 
  UserInfoMapper 在继承 BaseMapper 时, 指定了⼀个泛型, 这个UserInfo就是与数据库表相对应的实体类.
- 表名: 实体类的驼峰表⽰法转换成蛇形表⽰法(下划线分割), 作为表名. ⽐如UserInfo -> user_info
 - 字段: 根据实体类的属性名 转换为蛇形表⽰法作为字段名. ⽐如deleteFlag -> delete_flag
 - 主键: 默认为id
 
2.3.1@TableName
修改实体类名UserInfo为 Userinfo
 
 从⽇志可以看到, 默认查找的表名为userinfo
@Data
@TableName("user_info")
public class UserInfo {
    @TableId
    private Integer id;
    private String username ;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    @TableField("delete_flag")
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}
 
2.3.2@TableField
修改属性名 deleteFlag 为 deleteflag
 
 ⽇志可以看到, 根据属性名转换前的字段名为: deleteflag
@Data
@TableName("user_info")
public class UserInfo {
    @TableId
    private Integer id;
    private String username ;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    @TableField("delete_flag")
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}
 
2.3.3 @TableId
修改属性名 id 为 userId
运⾏结果:
 
可以通过 @TableId 来 指定对应的主键
@Data
@TableName("user_info")
public class UserInfo {
    @TableId
    private Integer id;
    private String username ;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    @TableField("delete_flag")
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
} 
如果属性名和字段名不⼀致, 需要在 @TableId 指明对应的字段名属性名和字段⼀致的情况下, 直接加 @TableId 注解就可以.
2.4打印日志
添加文件配置即可
mybatis-plus:
  # 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
    mapper-locations: classpath:mybatis/**Mapper.xml
  # 配置打印 MyBatis日志
    configuration:
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      map-underscore-to-camel-case: true #配置驼峰⾃动转换 
2.5条件构造器
⼊⻔程序⾥的使⽤, 都是简单的CRUD, 在实际的应⽤场景中, 我们还需要使⽤更复杂的操作, MyBatisPlus 也给我们提供了相应的⽀持.
MyBatis-Plus 提供了⼀套强⼤的条件构造器(Wrapper), ⽤于构建复杂的数据库查询条件. Wrapper 类允许开发者以链式调⽤的⽅式构造查询条件, ⽆需编写繁琐的 SQL 语句, 从⽽提⾼开发效率并减少 SQL 注⼊的⻛险
以下是主要的 Wrapper 类及其功能:
- AbstractWrapper:这是⼀个抽象基类, 提供了所有 Wrapper 类共有的⽅法和属性. 详细参考官⽹ 介绍: 条件构造器
 - QueryWrapper:⽤于构造查询条件, 在AbstractWrapper的基础上拓展了⼀个select⽅法, 允许指 定查询字段.
 - UpdateWrapper: ⽤于构造更新条件, 可以在更新数据时指定条件.
 - LambdaQueryWrapper:基于 Lambda 表达式的查询条件构造器, 它通过 Lambda 表达式来引⽤ 实体类的属性,从⽽避免了硬编码字段名.
 - LambdaUpdateWrapper: 基于 Lambda 表达式的更新条件构造器, 它允许你使⽤ Lambda 表达 式来指定更新字段和条件,同样避免了硬编码字段名的问题
 
2.5.1QueryWrapper
QueryWrapper并不只⽤于查询语句, ⽆论是修改, 删除, 查询, 都可以使⽤QueryWrapper来构建查询条件.
查询操作
完成下述SQL查询:
SELECT id,username,password,age FROM user_info WHERE age = 18 AND username 
"%min%" 
测试代码:
  @Test
    void testQueryWrapper(){
        QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>()
                .select("id","username","password","age")
                .eq("age",18)
                .like("username", "min");
        List<UserInfo> userInfos = userInfoMapper.selectList(userInfoQueryWrapper);
        userInfos.forEach(System.out::println);
    } 
注意:
默认情况下Mybatis-Plus会根据 @TableFiled ⽣成别名, 当指定了QueryWrapper的select属性后就仅仅是属性值⽽没有了别名. 查询出来的结果会对应不上
解决办法:
- ⾃⼰写⾃定义SQL
 - 实体类名和字段名保持⼀致
 - 不指定QueryWrapper的select字段
 - 使⽤LambdaQueryWrapper实现
 
更新
UPDATE user_info SET delete_flag=? WHERE age < 20测试代码:@Test void testUpdateByQueryWrapper(){ QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>() .lt("age", 20); UserInfo userInfo = new UserInfo(); userInfo.setDeleteFlag(1); userInfoMapper.update(userInfo, userInfoQueryWrapper); }
- lt : "less than" 的缩写,表⽰⼩于.
 - le : "less than or equal to"的缩写, 表⽰⼩于等于
 - ge : "greater than or equal to" 的缩写, 表⽰⼤于等于.
 - gt : "greater than" 的缩写, 表⽰⼤于.
 - eq : "equals" 的缩写, 表⽰等于.
 - ne : "not equals" 的缩写, 表⽰不等于
 
删除
完成下述SQL查询
DELETE FROM user_info WHERE age = 18测试代码:
@Test void testDeleteByQueryWrapper(){ QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>() .eq("age",18); userInfoMapper.delete(userInfoQueryWrapper); }
2.5.2UpdateWrapper
对于更新, 我们也可以直接使⽤ UpdateWrapper, 在不创建实体对象的情况下, 直接设置更新字段和条 件.
基础更新:完成下述SQL查询:UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)测试代码:
@Test void testUpdateByUpdateWrapper(){ UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>() .set("delete_flag",0) .set("age", 5) .in("id", List.of(1,2,3)); userInfoMapper.update(updateWrapper); }
完成下述SQL查询:UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)测试代码:
@Test void testUpdateBySQLUpdateWrapper(){ UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>() .setSql("age = age+10") .in("id", List.of(1,2,3)); userInfoMapper.update(updateWrapper); }
2.5.3LambdaQueryWrapper
QueryWrapper 和 UpdateWrapper存在⼀个问题, 就是需要写死字段名, 如果字段名发⽣变更, 可能会 因为测试不到位酿成事故.
MyBatis-Plus 给我们提供了⼀种基于Lambda表达式的条件构造器, 它通过 Lambda 表达式来引⽤实体 类的属性,从⽽避免了硬编码字段名, 也提⾼了代码的可读性和可维护性
- LambdaQueryWrapper
 - LambdaUpdateWrapper
 分别对应上述的QueryWrapper和UpdateWrapper
具体使用:
@Test void testLambdaQueryWrapper(){ QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>(); queryWrapper.lambda() .select(UserInfo::getUsername, UserInfo::getPassword,UserInfo::getAge) .eq(UserInfo::getUserId, 1); userInfoMapper.selectList(queryWrapper).forEach(System.out::println); }
2.5.4 LambdaUpdateWrapper
LambdaUpdateWrapper⽤法和 LambdaQueryWrapper相似
@Test
    void testLambdUpdateByUpdateWrapper(){
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>();
        updateWrapper.lambda()
                .set(UserInfo::getDeleteFlag, 0)
                .set(UserInfo::getAge, 5)
                .in(UserInfo::getUserId, List.of(1,2,3));
        userInfoMapper.update(updateWrapper);
    } 
2.6⾃定义SQL
在实际的开发中, MyBatis-Plus提供的操作不能满⾜我们的实际需求, MyBatis-Plus 也提供了⾃定义 SQL的功能, 我们可以利⽤Wrapper构造查询条件, 再结合Mapper编写SQL
要使用自定义SQL的功能 MyBatis-Plus版本号不得低于 3.0.7
示例1:
完成下述SQL查询
select id,username,password,age FROM user_info WHERE username = "admin" 
Mappe接口代码:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
    @Select("select id,username,password,age FROM user_info ${ew.customSqlSegment}")
    List<UserInfo> queryUserByCustom(@Param(Constants.WRAPPER)Wrapper<UserInfo> wrapper);
} 
@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    UserInfoMapper userInfoMapper;
    @Test
    void queryUserByCustom() {
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>().eq("username","admin");
        userInfoMapper.queryUserByCustom(queryWrapper).forEach(System.out::println);
    }
} 
 
- 参数命名:在⾃定义 SQL 时, 传递 Wrapper 对象作为参数时, 参数名必须为 ew ,或者使⽤注解 @Param(Constants.WRAPPER) 明确指定参数为 Wrapper 对象.
 - 使⽤ ${ew.customSqlSegment} :在 SQL 语句中,使⽤ ${ew.customSqlSegment} 来 引⽤ Wrapper 对象⽣成的 SQL ⽚段.
 - 不⽀持基于 entity 的 where 语句:⾃定义 SQL 时,Wrapper 对象不会基于实体类⾃动⽣成 where ⼦句,你需要⼿动编写完整的 SQL 语句
 
示例二 XML的⽅式完成
MyBatis-Plus 在 MyBatis 的基础上只做增强不做改变, 所以也⽀持XML的实现⽅式
上述功能也可以使⽤XML的⽅式完成
1.配置mapper路径 :
mybatis-plus:
 mapper-locations: "classpath*:/mapper/**.xml" # Mapper.xml 
2.mapper接口方法:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
    List<UserInfo> queryUserByCustom(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);
} 
3.编写XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatisplus.mapper.UserInfoMapper">
    <select id="queryUserByCustom" resultType="com.example.mybatisplus.mode.UserInfo">
         select * from user_info ${ew.customSqlSegment}
    </select>
</mapper> 
4.测试
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mybatisplus.mode.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    UserInfoMapper userInfoMapper;
    
    @Test
    void queryUserByCustom() {
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>()
                .eq("userName","lisi");
        userInfoMapper.queryUserByCustom(queryWrapper).forEach(System.out::println);
    }
} 
测试结果:
示例三:使用注解的方式
UPDATE user_info SET age = age+10 WHERE id IN (1,2,3) 
 mapper接口方法:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
    
    @Update("UPDATE user_info SET age = age+ #{addAge} ${ew.customSqlSegment}")
    void updateUserByCustom(@Param("addAge") int addAge, @Param("ew")Wrapper<UserInfo> wrapper);
} 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mybatisplus.mode.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    UserInfoMapper userInfoMapper;
    
    @Test
    void updateUserByCustom() {
        QueryWrapper<UserInfo> queryWrapper =new QueryWrapper<UserInfo>()
                .in("id", List.of(1,2,3));
        //目的把id为1,2,3  在原先年龄的基础上加10
        userInfoMapper.updateUserByCustom(10,queryWrapper);
    }
} 
  测试结果:

MyBatis-Plus总结:
- MyBatis-Plus 是 MyBatis 的增强⼯具, 在 MyBatis 的基础上只做增强不做改变, 可以⽤更少的代码实现数据库表的CRUD, 让我们的开发变得更加简单
  MyBatis-Plus ⽀持⾃定义SQL, 版本不低于3.0.7, 传递 Wrapper 对象作为参数时, 参数名必须为 ew,在 SQL 语句中,使⽤ ${ew.customSqlSegment} 来引⽤ Wrapper 对象⽣成的 SQL ⽚段

















![[BrainShadow-V1] VR头戴设备统计报告](https://i-blog.csdnimg.cn/direct/eeab3db06983452f88779fcb6e9f3da1.png)

