Mybatis 进阶 / Mybatis—Puls (详细)

news2025/1/19 1:04:56

目录

一.动态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>

 

注解⽅式(不推荐) 

把上⾯SQL(包括标签), 使⽤ <script></script> 标签括起来就可以
@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> 标签

之前的插⼊⽤⼾功能,只是有⼀个 gender 字段可能是选填项,如果有多个字段,⼀般考虑使⽤标签结 合标签,对多个字段都采取动态⽣成的⽅式。
标签中有如下属性:
  • 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接口代码:
@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片段 ,就可以加入<sql>标签完成复用
<sql id="allColumn">
 id, username, age, gender, phone, delete_flag, create_time, update_time
</sql>
通过 <include> 标签在原来抽取的地⽅进⾏引⽤。操作如下:
 <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操作数据库的步骤:

  1. 准备⼯作(数据准备, 项⽬准备, 引⼊依赖, 配置数据库连接信息)
  2. 编码(数据库表对应的实体类, 以及数据操作的Mapper⽂件)
  3. 测试

 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只需要继承这个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的代码:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {

}
UserInfoMapper 在继承 BaseMapper 时, 指定了⼀个泛型, 这个UserInfo就是与数据库表相对应的实体类.
MyBatis-Plus会根据这个实体类来推断表的信息.
默认情况下:
  1. 表名: 实体类的驼峰表⽰法转换成蛇形表⽰法(下划线分割), 作为表名. ⽐如UserInfo -> user_info
  2. 字段: 根据实体类的属性名 转换为蛇形表⽰法作为字段名. ⽐如deleteFlag -> delete_flag
  3. 主键: 默认为id

 2.3.1@TableName

修改实体类名UserInfo为 Userinfo
运⾏结果:

从⽇志可以看到, 默认查找的表名为userinfo 

可以通过 @TableName 来标识实体类对应的表
@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

可以通过 @TableField 来标识 对应的字段名

 

@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属性后
就仅仅是属性值⽽没有了别名. 查询出来的结果会对应不上

解决办法:

  1. ⾃⼰写⾃定义SQL
  2. 实体类名和字段名保持⼀致
  3. 不指定QueryWrapper的select字段
  4. 使⽤LambdaQueryWrapper实现
更新 
完成下述SQL查询操作:
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更新:
完成下述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);
    }
}

测试结果:

 示例三:使用注解的方式

完成下述SQL查询
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 ⽚段

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java工具包:高效开发的魔法钥匙

目录 一、引言 二、Hutool 工具包初体验 2.1 快速入门 2.2 常用工具类及方法详解 2.2.1 Convert 类型转换工具类 2.2.2 DateUtil 日期时间工具类 2.2.3 StrUtil 字符串工具类 2.2.4 其他常用工具类 三、其他 Java 常用工具包巡礼 3.1 Apache Commons 系列 3.2 Google…

Formality:参考设计/实现设计以及顶层设计

相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482​​​ Formality存在两个重要的概念&#xff1a;参考设计/实现设计和顶层设计&#xff0c;本文就将对此进行详细阐述。参考设计/实现设计是中两个重要的全局概念&am…

HBase实训:纸币冠字号查询任务

一、实验目的 1. 理解分布式数据存储系统HBase的架构和工作原理。 2. 掌握HBase表的设计原则&#xff0c;能够根据实际业务需求设计合理的表结构。 3. 学习使用HBase Java API进行数据的插入、查询和管理。 4. 实践分布式数据存储系统在大数据环境下的应用&#xff0c;…

C#轻松实现条形码二维码生成及识别

一、前言 大家好&#xff01;我是付工。 今天给大家分享一下&#xff0c;如何基于C#来生成并识别条形码或者二维码。 二、ZXing.Net 实现二维码生成的库有很多&#xff0c;我们这里采用的是http://ZXing.Net。 ZXing是一个开放源码的&#xff0c;用Java实现的多种格式的一…

重拾Python学习,先从把python删除开始。。。

自己折腾就是不行啊&#xff0c;屡战屡败&#xff0c;最近终于找到前辈教我 第一步 删除Python 先把前阵子折腾的WSL和VScode删掉。还是得用spyder&#xff0c;跟matlab最像&#xff0c;也最容易入手。 从VScode上搞python&#xff0c;最后安装到appdata上&#xff0c;安装插…

ASP.NET Core - 依赖注入(三)

ASP.NET Core - 依赖注入&#xff08;三&#xff09; 4. 容器中的服务创建与释放 4. 容器中的服务创建与释放 我们使用了 IoC 容器之后&#xff0c;服务实例的创建和销毁的工作就交给了容器去处理&#xff0c;前面也讲到了服务的生命周期&#xff0c;那三种生命周期中对象的创…

高通8255 Android STR 启动失败要因分析调查

目录 背景&#xff1a; 调查过程&#xff1a; 步骤1&#xff1a; slog2info | grep vmm_service 步骤2&#xff1a; slog2info | grep qvm 总结&#xff1a; 解决方案 背景&#xff1a; 调试高通8255 STR的STR过程中发现Android和QNX进入STR状态后&#xff0c;脱出STR时…

Linux操作命令之云计算基础命令

一、图形化界面/文本模式 ctrlaltF2-6 图形切换到文本 ctrlalt 鼠标跳出虚拟机 ctrlaltF1 文本切换到图形 shift ctrl "" 扩大 ctrl "-" 缩小 shift ctrl "n" 新终端 shift ctrl "t" 新标签 alt 1,…

LabVIEW桥接传感器配置与数据采集

该LabVIEW程序主要用于配置桥接传感器并进行数据采集&#xff0c;涉及电压激励、桥接电阻、采样设置及错误处理。第一个VI&#xff08;"Auto Cleanup"&#xff09;用于自动清理资源&#xff0c;建议保留以确保系统稳定运行。 以下是对图像中各个组件的详细解释&#…

面试题解析

1、写一个sed命令&#xff0c;修改/tmp/input.txt文件的内容 要求&#xff1a; 删除所有空行&#xff1b; 在非空行前面加一个"AAA"&#xff0c;在行尾加一个"BBB"&#xff0c;即将内容为11111的一行改为&#xff1a;AAA11111BBB 创造测试文件&#xff1a;…

合合信息名片全能王上架原生鸿蒙应用市场,成为首批数字名片类应用

长期以来&#xff0c;名片都是企业商务沟通的重要工具。随着企业数字化转型&#xff0c;相较于传统的纸质名片&#xff0c;数字名片对于企业成员拓展业务、获取商机、提升企业形象等方面发挥着重要作用。近期&#xff0c;合合信息旗下名片全能王正式上线原生鸿蒙应用市场&#…

【日志篇】(7.6) ❀ 01. 在macOS下刷新FortiAnalyzer固件 ❀ FortiAnalyzer 日志分析

【简介】FortiAnalyzer 是 Fortinet Security Fabric 安全架构的基础&#xff0c;提供集中日志记录和分析&#xff0c;以及端到端可见性。因此&#xff0c;分析师可以更有效地管理安全状态&#xff0c;将安全流程自动化&#xff0c;并快速响应威胁。具有分析和自动化功能的集成…

《汽车维修技师》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答&#xff1a; 问&#xff1a;《汽车维修技师》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《汽车维修技师》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a;北方联合出版传媒&#xff08;…

【OpenCV(C++)快速入门】--opencv学习

0 配置环境 配置环境网上很多资料&#xff0c;这里就不赘述了。 笔者使用的是VS2022opencv4.9.0 测试配置环境 // 打开摄像头样例 #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/imgcodecs/imgcod…

Python编程与在线医疗平台数据挖掘与数据应用交互性研究

一、引言 1.1 研究背景与意义 在互联网技术飞速发展的当下,在线医疗平台如雨后春笋般涌现,为人们的就医方式带来了重大变革。这些平台打破了传统医疗服务在时间和空间上的限制,使患者能够更加便捷地获取医疗资源。据相关报告显示,中国基于互联网的医疗保健行业已进入新的…

网安快速入门之Windows命令

在Windows中 我们今天介绍几个命令&#xff1a; help copy dir cd type del ipconfig net netstat tasklist sc1. help 显示命令的帮助信息。或者显示Windows内置命令。 常用参数&#xff1a; <命令>&#xff1a;查看指定命令的帮助。 示例&#xff1a;help copy 显…

python convert.py -s Rubble

E0222 12:08:50.144686 1326795 logging.cc:56] [option_manager.cc:813] Check failed: ExistsDir(*image_path) E0222 12:08:50.144773 1326795 option_manager.cc:879] Invalid options provided. ERROR:root:Feature extraction failed with code 256. Exiting.在运行pytho…

[BrainShadow-V1] VR头戴设备统计报告

Brain-Shadow-V1 EventVR headsetsReported byXiao enDate2025/01/15Version1.0 HTC Vive Pro 2 Pro HTC Vive Pro 2 是一款高端虚拟现实头显&#xff0c;配备双 2.5K 显示屏&#xff0c;组合分辨率达到 48962448&#xff0c;提供 120 的视场角和 120Hz 的刷新率。该设备支持…

多监控m3u8视频流,怎么获取每个监控的封面图(纯前端)

文章目录 1.背景2.问题分析3.解决方案3.1解决思路3.2解决过程3.2.1 封装播放组件3.2.2 隐形的视频div3.2.3 截取封面图 3.3 结束 1.背景 有这样一个需求&#xff1a; 给你一个监控列表&#xff0c;每页展示多个监控&#xff08;至少12个&#xff0c;m3u8格式&#xff09;&…

Golang Gin系列-2:搭建Gin 框架环境

开始网络开发之旅通常是从选择合适的工具开始的。在这个全面的指南中&#xff0c;我们将引导你完成安装Go编程语言和Gin框架的过程&#xff0c;Gin框架是Go的轻量级和灵活的web框架。从设置Go工作空间到将Gin整合到项目中&#xff0c;本指南是高效而强大的web开发路线图。 安装…