Mybatis 进阶 / Mybatis—Puls (详细)

目录

一.动态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字段有默认值, 就会设置为默认值

测试代码:

@Testvoid 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

测试代码:

 查询条件我只写了一个,可以写多个的

 @Testvoid 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" ,并打印

   @Testvoid 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_infowhere id in<foreach collection="list" item="id" separator="," open="(" close=")">#{id}</foreach></delete>

测试代码:

    @Testvoid 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:#数据库连接的urlurl: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false#连接数据库的⽤⼾名username: root#连接数据库的⽤⼾名password: 123456driver-class-name: com.mysql.cj.jdbc.Drivermybatis-plus:# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件mapper-locations: classpath:mybatis/**Mapper.xml# 配置打印 MyBatis日志configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-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 {@TableIdprivate 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 {@AutowiredUserInfoMapper userInfoMapper;@Testvoid contextLoads() {System.out.println(userInfoMapper.selectById(1));}@Testvoid testInsert() {UserInfo user = new UserInfo();user.setUsername("bite");user.setPassword("123456");user.setAge(11);user.setGender(0);user.setPhone("18610001234");userInfoMapper.insert(user);}@Testvoid testSelectById() {UserInfo user = userInfoMapper.selectById(1L);System.out.println("user: " + user);}@Testvoid testSelectByIds() {List<UserInfo> users = userInfoMapper.selectBatchIds(List.of(1L, 2L, 3L,4L));users.forEach(System.out::println);}@Testvoid 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 {@TableIdprivate 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 {@TableIdprivate 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 {@TableIdprivate 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.StdOutImplmap-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%"

测试代码:

  @Testvoid 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
测试代码:
  @Testvoid 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

测试代码:

 @Testvoid 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)

测试代码:

 @Testvoid 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)

测试代码:

 @Testvoid 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 

 具体使用:

@Testvoid 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相似
@Testvoid 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 {@AutowiredUserInfoMapper userInfoMapper;@Testvoid 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 {@AutowiredUserInfoMapper userInfoMapper;@Testvoid 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 {@AutowiredUserInfoMapper userInfoMapper;@Testvoid updateUserByCustom() {QueryWrapper<UserInfo> queryWrapper =new QueryWrapper<UserInfo>().in("id", List.of(1,2,3));//目的把id为1,2,3  在原先年龄的基础上加10userInfoMapper.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.mzph.cn/news/893125.shtml

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

相关文章

Go 切片:用法和本质

要想更好的了解一个知识点&#xff0c;实战是最好的经历。 题目 我这里放一道题目&#xff1a; package mainimport "fmt"func SliceRise(s []int) {s append(s, 0)for i : range s {s[i]}fmt.Println(s) }func SlicePrint() {s1 : []int{1, 2}s2 : s1s2 append…

如何下载对应城市的地理json文件

这里采用的是阿里地图工具进行查找&#xff1a; DataV.GeoAtlas地理小工具系列 由阿里云DataV数据可视化团队出品,多年深耕数据可视化领域,数据大屏业务开拓者和领航者。致力用震撼而清晰的视觉语言,让更多人读懂大数据,受惠数据驱动的决策方式 第一步打开网站 &#xff1a; …

AI 大爆发时代,音视频未来路在何方?

AI 大模型突然大火了 回顾2024年&#xff0c;计算机领域最大的变革应该就是大模型进一步火爆了。回顾下大模型的发展历程&#xff1a; 萌芽期&#xff1a;&#xff08;1950-2005&#xff09; 1956年&#xff1a;计算机专家约翰麦卡锡首次提出“人工智能”概念&#xff0c;标志…

解决wordpress媒体文件无法被搜索的问题

最近,我在wordpress上遇到了一个令人困扰的问题:我再也无法在 WordPress 的媒体库中搜索媒体文件了。之前,搜索媒体非常方便,但现在无论是图片还是其他文件,似乎都无法通过名称搜索到。对于我这样需要频繁使用图片的博主来说,这简直是个大麻烦。 问题源头 一开始,我怀…

代码随想录训练营第五十一天| 99.岛屿数量 深搜 岛屿数量 广搜 100.岛屿的最大面积

99.岛屿数量 深搜 题目链接&#xff1a;99. 岛屿数量 讲解链接&#xff1a;代码随想录 就是dfs模版题目 在dfs里可以先定义方向数组移动 再遍历分别向四个方向移动 同时记得更新当前nextx nexty 再判断是否越界 再执行判断条件 当前位置未走过 visited[i][j] false 一开始jav…

springboot之YAML语法

目录 一、基本语法 写一个端口号和一个路径 Controller里的方法&#xff1a; 然后这样写才能访问到&#xff1a; 这是在yml里面写的&#xff0c;也可以写在properties里 再访问&#xff1a; 二、值的写法 1.普通类型(数字、字符串、布尔) 例子1&#xff1a; 配置文件…

ASP .NET Core 学习 (.NET 9)- 创建 API项目,并配置Swagger及API 分组或版本

本系列为个人学习 ASP .NET Core学习全过程记录&#xff0c;基于.NET 9 和 VS2022 &#xff0c;实现前后端分离项目基础框架搭建和部署&#xff0c;以简单、易理解为主&#xff0c;注重页面美观度和后台代码简洁明了&#xff0c;可能不会使用过多的高级语法和扩展&#xff0c;后…

LuaJIT Garbage Collector Algorithms

Explain 本篇文章是对Make Pall发表wili内容《LuaJIT 3.0 new Garbage Collector》的翻译和扩展&#xff0c;因为原文是对LuaJIT 2.x GC重要功能的简介和对LuaJIT 3.0 new GC的工作计划&#xff0c;所以它并不是系统性介绍GC的文章。希望以后能有精力系统性的对LuaJIT 2.x GC做…

ChatGPT大模型极简应用开发-CH1-初识 GPT-4 和 ChatGPT

文章目录 1.1 LLM 概述1.1.1 语言模型和NLP基础1.1.2 Transformer及在LLM中的作用1.1.3 解密 GPT 模型的标记化和预测步骤 1.2 GPT 模型简史&#xff1a;从 GPT-1 到 GPT-41.2.1 GPT11.2.2 GPT21.2.3 GPT-31.2.4 从 GPT-3 到 InstructGPT1.2.5 GPT-3.5、Codex 和 ChatGPT1.2.6 …

基于单片机的直流电机控制系统(论文+源码)

1 系统方案设计 本设计基于单片机的直流电机控制系统的总体架构设计如图2.1所示&#xff0c;其采用STM32F103单片机作为控制器&#xff0c;结合ESP8266 WiFi通信模块、L9110电机驱动电路、OLED液晶、按键等构成整个系统。用户在使用时&#xff0c;可以通过按键或者手机APP设定直…

【Linux】Linux入门(2)常见指令

目录 Linux下的文件ls 指令 --- 展示目录pwd指令 --- 显示当前目录cd 指令 --- 改变工作目录touch指令 --- 创建普通文件stat指令 --- 查看文件属性mkdir指令 --- 创建目录rmdir指令 --- 删除目录rm指令 --- 同时删除文件或目录man指令 --- 访问帮助手册cp指令 复制文件或目录m…

《自动驾驶与机器人中的SLAM技术》ch4:基于预积分和图优化的 GINS

前言&#xff1a;预积分图优化的结构 1 预积分的图优化顶点 这里使用 《自动驾驶与机器人中的SLAM技术》ch4&#xff1a;预积分学 中提到的散装的形式来实现预积分的顶点部分&#xff0c;所以每个状态被分为位姿&#xff08;&#xff09;、速度、陀螺零偏、加计零偏四种顶点&am…

BMC知识框图

OpenBMC简介 OpenBMC作为BMC的Linux发行版&#xff0c;旨在管理广泛系统&#xff0c;如企业、高性能计算、电信和大规模数据中心。 BMC&#xff0c;或Baseboard Manager Controller&#xff0c;是服务器主板上的专用微控制器&#xff0c;采用IPMI架构&#xff0c;具备智能性&…

书生大模型基础岛第五关

基础任务&#xff1a;使用 XTuner 微调 InternLM2-Chat-7B 实现自己的小助手认知&#xff0c;如下图所示&#xff08;图中的尖米需替换成自己的昵称&#xff09;&#xff0c;记录复现过程并截图。 1.配置环境 2.修改数据&#xff0c;将尖米修改为人工智能小助手 修改之前 修改…

EI Scopus双检索 | 2025年第四届信息与通信工程国际会议(JCICE 2025)

会议简介 Brief Introduction 2025年第四届信息与通信工程国际会议(JCICE 2025) 会议时间&#xff1a;2025年7月25日-27日 召开地点&#xff1a;中国哈尔滨 大会官网&#xff1a;www.jcice.org 由黑龙江大学和成都信息工程大学主办&#xff0c;江苏科技大学协办的2025年第四届信…

于灵动的变量变幻间:函数与计算逻辑的浪漫交织(下)

大家好啊&#xff0c;我是小象٩(๑ω๑)۶ 我的博客&#xff1a;Xiao Xiangζั͡ޓއއ 很高兴见到大家&#xff0c;希望能够和大家一起交流学习&#xff0c;共同进步。 这一节我们主要来学习单个函数的声明与定义&#xff0c;static和extern… 这里写目录标题 一、单个函数…

Python Pyside6 加Sqlite3 写一个 通用 进销存 系统 初型

图: 说明: 进销存管理系统说明文档 功能模块 1. 首页 显示关键业务数据商品总数供应商总数本月采购金额本月销售金额显示预警信息库存不足预警待付款采购单待收款销售单2. 商品管理 商品信息维护商品编码(唯一标识)商品名称规格型号单位分类进货价销售价库存数量预警…

2025西湖论剑-babytrace

前言 就做了下题目&#xff0c;pwn1/3 都是签到&#xff0c;pwn2 后面绕 ptrace 有点意思&#xff0c;简单记录一下 漏洞分析 子进程中的读/写功能没有检查负数的情况&#xff0c;存在越界读写&#xff1a; void __fastcall get_value(__int64 *int64_arr) {__int64 ll; //…

西门子【Library of Basic Controls (LBC)基本控制库”(LBC) 提供基本控制功能】

AF架构中使用的库 文章目录 Table of contents Legal information ..............................................................................................................................2 1 Introduction ................................................…

Phi小模型开发教程:用C#开发本地部署AI聊天工具,只需CPU,不需要GPU,3G内存就可以运行,不输GPT-3.5

大家好&#xff0c;我是编程乐趣。 行业诸多大佬一直在说&#xff1a;“‌2025年将是AI应用元年‌”&#xff0c;虽然说大佬的说法不一定对&#xff0c;但AI趋势肯定没错的。 对于我们程序员来说&#xff0c;储备AI应用开发技能&#xff0c;不管对找工作、接项目、创业肯定是…