当前位置: 首页 > news >正文

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 ⽚段

相关文章:

Mybatis 进阶 / Mybatis—Puls (详细)

目录 一.动态SQL 1.1标签 1.2 标签 1.3标签 1.4标签 1.5标签 1.6标签 mybatis总结&#xff1a; 二.Mybatis-Puls 2.1准备工作 2.2CRUD单元测试 2.2.1创建UserInfo实体类 2.2.2编写Mapper接⼝类 2.2.3 测试类 2.3 常见注解 2.3.1TableName 2.3.2TableField 2.4打印日…...

opencv在图片上添加中文汉字(c++以及python)

opencv在图片上添加中文汉字&#xff08;c以及python&#xff09;_c opencv绘制中文 知乎-CSDN博客 环境&#xff1a; ubuntu18.04 desktopopencv 3.4.15 opencv是不支持中文的。 这里C代码是采用替换原图的像素点来实现的&#xff0c;实现之前我们先了解一下汉字点阵字库。…...

js截取video视频某一帧为图片

1.代码如下 <template><div class"box"><div class"video-box"><video controls ref"videoRef" preload"true"src"https://qt-minio.ictshop.com.cn:9000/resource-management/2025/01/08/7b96ac9d957c45a…...

Observability:最大化可观察性 AI 助手体验的 5 大提示(prompts)

作者&#xff1a;来自 Elastic Zoia_AUBRY 在过去三年担任客户工程师期间&#xff0c;我遇到了数百名客户&#xff0c;他们最常问的问题之一是&#xff1a;“我的数据在 Elastic 中&#xff1b;我该如何利用它获得最大优势&#xff1f;”。 如果这适用于你&#xff0c;那么本…...

HDFS的架构优势与基本操作

目录 写在前面一、 HDFS概述 1.1 HDFS简介1.2 HDFS优缺点 1.2.1 优点1.2.2 缺点 1.3 HDFS组成架构1.4 HDFS文件块大小 二、HDFS的Shell操作&#xff08;开发重点&#xff09; 2.1 基本语法2.2 命令大全2.3 常用命令实操 2.3.1 上传2.3.2 下载2.3.3 HDFS直接操作 三、HDFS的AP…...

hive表修改字段类型没有级连导致历史分区报错

一&#xff1a;问题背景 修改hive的分区表时有级连概念&#xff0c;指字段的最新状态&#xff0c;默认只对往后的分区数据生效&#xff0c;而之前的分区保留历史元数据状态。好处就是修改语句的效率很快&#xff0c;坏处就是如果历史分区的数据还有用&#xff0c;那就回发生分…...

023:到底什么是感受野?

本文为合集收录&#xff0c;欢迎查看合集/专栏链接进行全部合集的系统学习。 合集完整版请查看这里。 在前面介绍卷积算法时&#xff0c;一直在强调一个内容&#xff0c;那就是卷积算法的运算过程是—— 卷积核在输入图像上滑动扫描的过程。 在每一次扫描时&#xff0c;可以…...

GoFrame g.* 方法和数据类型

GoFrame g.* 方法和数据类型 GoFrame 框架通过 g.* 方法提供了一系列常用的数据类型和对象获取方法。这个模块采用强耦合设计&#xff0c;目的是为开发者提供便捷的类型和对象调用方式。 使用方式 import "github.com/gogf/gf/v2/frame/g"数据类型 基础类型别名 …...

分苹果,若a ^ b ^ c = 0意味着:a 和 (b ^ c) 的值相等,或者 b 和 (a ^ c) 的值相等,以及 c 和 (a ^ b) 的值相等。

若a ^ b ^ c faultSum&#xff0c;那么faultSum 0时&#xff0c;即可产生上面的平分方案。说明可以满足二进制平分 #include<bits/stdc.h> using namespace std; int main() { int n; cin>>n; vector<int> weight(n); for(int i0;i<n;i) {…...

深入解析人工智能中的协同过滤算法及其在推荐系统中的应用与优化

目录 什么是协同过滤算法核心原理基本步骤相似度计算代码实现详解1.流程图2.创建基础的数据结构存储用户评分数据3.计算用户相似度4.获取相似用户5.推荐方法 算法优化建议1. 数据预处理优化去除异常值和噪声数据进行数据标准化使用稀疏矩阵优化存储 2. 相似度计算优化使用局部敏…...

电梯系统的UML文档04

这个版本的类图是直接从4.2节中用例图的描述得来的&#xff0c;这个视图中的类覆盖了系统所有的功能。我们用电梯类和电梯控制器类&#xff08;ElevatorControl&#xff09;移动或停止电梯&#xff1b;用门类开门或关门&#xff1b;用指示器类让乘客知道电梯的位置和方向&#…...

《自动驾驶与机器人中的SLAM技术》ch4:预积分学

目录 1 预积分的定义 2 预积分的测量模型 ( 预积分的测量值可由 IMU 的测量值积分得到 ) 2.1 旋转部分 2.2 速度部分 2.3 平移部分 2.4 将预积分测量和误差式代回最初的定义式 3 预积分的噪声模型和协方差矩阵 3.1 旋转部分 3.2 速度部分 3.3 平移部分 3.4 噪声项合并 4 零偏的…...

海量数据的处理

一般来说都是针对数据量特别大&#xff0c;内存有限制的。 第一类&#xff1a;topk问题 比如&#xff0c;在海量数据中找前50大的数据怎么办&#xff1f; 方法一&#xff1a;使用小顶堆&#xff0c;用小顶堆维护这50个元素&#xff0c;当有新元素到来时&#xff0c;直接与堆…...

Python人脸识别库DeepFace使用教程及源码解析

目录 一、DeepFace介绍 1、人脸库设计 2、DeepFace.find 3、DeepFace.verify 4、DeepFace.analyze 5、DeepFace.extract_faces 6、DeepFace.represent 7、DeepFace.stream 二、DeepFace二次开发 1、开发活体检测API 2、模型权重持久化 三、总结 一、DeepFace介绍 …...

Nacos:使用PgSQL数据源

数据源插件开源仓库地址&#xff1a;nacos-datasource-extend-plugins 一、PostgreSQL数据库安装 1、本文使用Docker进行数据库的安装&#xff0c;使用docker命令拉取的PG14版本的数据库&#xff1a; docker pull postgres:14.6 2、创建PG容器并启动&#xff0c;映射了5432…...

基于Python的多元医疗知识图谱构建与应用研究(下)

五、基于医疗知识图谱的医疗知识图谱程序构建 5.1 数据层构建 5.1.1 数据源选择与获取 在构建基于医疗知识图谱的医疗知识图谱数据层时,数据源的选择与获取至关重要。数据源的质量和丰富度直接决定了知识图谱的可靠性和实用性。医学文献是重要的数据源之一,包括学术期刊论…...

JAVA:Spring Boot 实现责任链模式处理订单流程的技术指南

1、简述 在复杂的业务系统中&#xff0c;订单流程往往需要一系列的操作&#xff0c;比如验证订单、检查库存、处理支付、更新订单状态等。责任链模式&#xff08;Chain of Responsibility&#xff09;可以帮助我们将这些处理步骤分开&#xff0c;并且以链式方式处理每一个操作…...

SpringBoot多级配置文件

1.问题先导 有这样的场景&#xff0c;我们开发完毕后需要测试人员进行测试&#xff0c;由于测试环境和开发环境的很多配置都不相同&#xff0c;所以测试人员在运 行我们的工程时需要临时修改很多配置&#xff0c;如下 java –jar springboot.jar –-spring.profiles.activete…...

阿里云安装mikrotik7配置内网互通

阿里云近期推出了200M不限量机器&#xff0c;对于没有公网接入的中小企业可以借助这个机器对多地分支机构进行内网互通。目前已经有很多机构用这个搞跨云k8s,跨云集群了。 mikrotik作为一个商用的软件&#xff0c;操作性比一些开源的软件好用不少。 本文使用的网段为172.16.1…...

std::forward实现原理与应用场景

std::forward 是 C11 引入的一个函数模板&#xff0c;用于实现完美转发&#xff08;Perfect Forwarding&#xff09;。它的核心作用是根据传入的参数&#xff0c;决定将参数以左值引用还是右值引用的方式进行转发&#xff0c;从而保持参数的原始值类别。 实现原理 template&l…...

TiDB 在市面上的热门应用领域

TiDB 在市面上的热门应用领域 TiDB 作为一款分布式数据库&#xff0c;凭借其高可扩展性和强一致性&#xff0c;逐渐成为多个行业和领域的热门选择。那么&#xff0c;TiDB 在市面上主要应用在哪些领域呢&#xff1f;今天我们来看看 TiDB 在几个热门领域的应用场景。 1. 互联网…...

“深入浅出”系列之C++:(11)推荐一些C++的开源项目

1. SQLiteCpp - 简单易用的Sqlite C封装库 仓库地址&#xff1a;https://github.com/SRombauts/SQLiteCpp 简介&#xff1a;SQLiteCpp是一个对Sqlite数据库进行C封装的开源库&#xff0c;代码行数约2,500行。它提供了简洁易用的接口&#xff0c;使得在C项目中操作Sqlite数据库…...

高等数学学习笔记 ☞ 定积分的积分方法

1. 定积分的换元积分法 1. 换元积分公式&#xff1a;设函数在闭区间上连续&#xff0c;令&#xff0c;若满足&#xff1a; ①&#xff1a;当时&#xff0c;&#xff1b;当时&#xff0c;。 此时的大小关系不一定&#xff0c;但与最好对应着写&#xff0c;否则就要留意变号的问…...

KVA教程-插件开发

“如果结果不如你所愿&#xff0c;就在尘埃落定前奋力一搏。”——《夏目友人帐》 “有些事不是看到了希望才去坚持&#xff0c;而是因为坚持才会看到希望。”——《十宗罪》 “维持现状意味着空耗你的努力和生命。”——纪伯伦 KVA 技术教程 * 插件开发 简介 插件开发是KVA&a…...

AI守护煤矿安全生产:基于视频智能的煤矿管理系统架构解析

前言 本文我将介绍我和我的团队自主研发设计的一款AI产品的成果展示——“基于视频AI识别技术的煤矿安全生产管理系统”。 这款产品是目前我在创业阶段和几位矿业大学的博士共同从架构设计、开发到交付的全过程中首次在博客频道发布, 我之前一直想写但没有机会来整理这套系统的…...

AI编程工具横向评测--Cloudstudio塑造完全态的jupyter notebook助力数据分析应用开发

AI编程工具横向评测–Cloudstudio塑造完全态的jupyter notebook助力数据分析应用开发 数据分析类应用的开发&#xff0c;指的是首先进行数据分析&#xff0c;比如统计学分析、机器学习模型的构建等&#xff0c;然后将分析的流程开发成数据分析类的工具&#xff0c;或者将数据分…...

04JavaWeb——Maven-SpringBootWeb入门

Maven 课程内容 初识Maven Maven概述 Maven模型介绍 Maven仓库介绍 Maven安装与配置 IDEA集成Maven 依赖管理 01. Maven课程介绍 1.1 课程安排 学习完前端Web开发技术后&#xff0c;我们即将开始学习后端Web开发技术。做为一名Java开发工程师&#xff0c;后端Web开发…...

ThreeJS能力演示——界面点选交互能力

1、支持界面点选 点选模型整体思路是&#xff1a;根据camera位置作为起始点&#xff0c;叠加鼠标相对位置作为偏置&#xff0c;摄像头方向作为射线方向。 根据射线方向中的遇到的3D物体列表&#xff0c;第一个遇到的物体作为被点选的物体。 // 鼠标事件处理let selectedObjec…...

Linux:常用命令--文件与目录操作

ls命令 功能&#xff1a;&#xff08;list&#xff09;列出当前目录的文件信息 语法&#xff1a;ls [-l -h -a] [参数] 参数&#xff1a;被查看的文件夹&#xff0c;不提供参数&#xff0c;表示查看当前工作目录-l&#xff0c;以列表形式查看每个文件的属性&#xff0c;包含…...

Node.js NativeAddon 构建工具:node-gyp 安装与配置完全指南

Node.js NativeAddon 构建工具&#xff1a;node-gyp 安装与配置完全指南 node-gyp Node.js native addon build tool [这里是图片001] 项目地址: https://gitcode.com/gh_mirrors/no/node-gyp 项目基础介绍及主要编程语言 Node.js NativeAddon 构建工具&#xff08;node-gyp…...

docker运行Java项目,Kaptcha因为字体缺失没法显示验证码图片

2015工作至今&#xff0c;10年资深全栈工程师&#xff0c;CTO&#xff0c;擅长带团队、攻克各种技术难题、研发各类软件产品&#xff0c;我的代码态度&#xff1a;代码虐我千百遍&#xff0c;我待代码如初恋&#xff0c;我的工作态度&#xff1a;极致&#xff0c;责任&#xff…...

C++otlv4连接sql serveer使用记录(注意点)

C使用otlv4在做插入时&#xff0c;有一些设计的坑需要注意 插入数据&#xff1a; 当要给表中插入单个字符时&#xff0c;数据库表设计使用varchar(1)是合理的&#xff0c;但是otlv4一直报错char。 后续查很久才知道&#xff0c;otlv4所写的绑定的字符数组的长度应该实际数组…...

[思考记录]认知和思考

在以前&#xff0c;具备一定的技能和经验就能轻易找到自己的一席之地。但在AI时代下&#xff0c;这些东西很容易就被抹平&#xff0c;那么我们的竞争力又在哪里&#xff1f;“认知和思考”是一个方向&#xff0c;帮助我们能去应对复杂情境、帮我们更容易去看到真相。 1.很多时…...

前端开发Web

Ajax 概念:Asynchronous JavaScriptAnd XML&#xff0c;异步的JavaScript和XML 作用: 数据交换:通过Ajax可以给服务器发送请求&#xff0c;并获取服务器响应的数据。 异步交互:可以在不重新加载整个页面的情况下&#xff0c;与服务器交换数据并更新部分网页的…...

【C++提高篇】—— C++泛型编程之模板基本语法和使用的详解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、模板的概念二、函数模板2.1 函数模板的使用2.2 函数模板注意事项2.3 普通函数与函数模板的区别2.4 普通函数与函数模板的调用规则2.5 模板的局限性 三、类模…...

WPS计算机二级•高效操作技巧

听说这里是目录哦 斜线表头 展示项目名称&#x1f34b;‍&#x1f7e9;横排转竖排&#x1f350;批量删除表格空白行&#x1f348;方法一方法二建辅助列找空值 能量站&#x1f61a; 斜线表头 展示项目名称&#x1f34b;‍&#x1f7e9; 选中单元格&#xff0c;单击右键➡️“设…...

【Maui】视图界面与数据模型绑定

文章目录 前言一、问题描述二、解决方案三、软件开发&#xff08;源码&#xff09;3.1 创建模型3.2 视图界面3.3 控制器逻辑层 四、项目展示 前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移动和桌面应用。 使用 .NET MAUI&…...

vue3-sfc-loader 加载远程.vue文件(sfc)案例

注意事项 style标签如果增加了lang比如&#xff1a;lang“scss”&#xff0c;需要提供scss-loader的处理器&#xff0c;这个暂时没研究&#xff0c;我的处理方式是将动态模版的css放在了全局打包暂时还没有测试&#xff0c;后面测试了会同步更新 安装vue3-sfc-loader npm inst…...

Hadoop美食推荐系统 爬虫1.8w+数据 协同过滤余弦函数推荐美食 Springboot Vue Element-UI前后端分离

Hadoop美食推荐系统 爬虫1.8w数据 协同过滤余弦函数推荐美食 Springboot Vue Element-UI前后端分离 【Hadoop项目】 1. data.csv上传到hadoop集群环境 2. data.csv数据清洗 3.MapReducer数据汇总处理, 将Reducer的结果数据保存到本地Mysql数据库中 4. SpringbootEchartsMySQL 显…...

使用Linux驱动程序的fasync(文件异步通知机制)向用户空间发送SIGIO信号的学习记录

前言 本文学习使用Linux驱动程序的fasync(文件异步通知机制)向用户空间发送SIGIO信号。 fasync(文件异步通知机制)名字的来历 fasync 是 “file asynchronous” 的缩写&#xff0c;意思是 文件异步通知。 这里的文件是指文件结构体struct file *file &#xff0c;关于文件结…...

面试经验分享-回忆版某小公司

说说你项目中数据仓库是怎么分层的&#xff0c;为什么要分层&#xff1f; 首先是ODS层&#xff0c;连接数据源和数据仓库&#xff0c;数据会进行简单的ETL操作&#xff0c;数据来源通常是业务数据库&#xff0c;用户日志文件或者来自消息队列的数据等 中间是核心的数据仓库层&a…...

【算法学习笔记】35:扩展欧几里得算法求解线性同余方程

线性同余方程问题 线程同余方程问题是指 a x ≡ b ( m o d m ) ax \equiv b~(mod~m) ax≡b (mod m)&#xff0c;给定 a a a、 b b b和 m m m&#xff0c;找到一个整数 x x x使得该方程成立&#xff0c;即使得 a x m o d m b ax~mod~mb ax mod mb&#xff0c;随便返回任何一个…...

ent.SetDatabaseDefaults()

在 AutoCAD 的 .NET API 中&#xff0c;ent.SetDatabaseDefaults() 这句代码通常用于将一个实体&#xff08;Entity&#xff09;对象的属性设置为与其所在的数据库&#xff08;Database&#xff09;的默认设置相匹配。这意味着&#xff0c;该实体将采用数据库级别的默认颜色、图…...

使用docker部署tomcat服务器和mysql数据库

使用docker部署tomcat服务器 1、拉去tomcat镜像 [rootlocalhost yum.repos.d]# sudo docker pull docker.io/tomcat:9 9: Pulling from library/tomcat de44b265507a: Pull complete 4c2afd91a87d: Pull complete 89e9bbcfa697: Pull complete 11be3e613582: Pull complet…...

Jenkins 启动

废话 这一阵子感觉空虚&#xff0c;心里空捞捞的&#xff0c;总想找点事情做&#xff0c;即使这是一件微小的事情&#xff0c;空余时间除了骑车、打球&#xff0c;偶尔朋友聚会 … 还能干什么呢&#xff1f; 当独自一人时&#xff0c;究竟可以做点什么&#xff0c;填补这空虚…...

Elasticsearch(ES)基础查询语法的使用

1. Match Query (全文检索查询) 用于执行全文检索&#xff0c;适合搜索文本字段。 { “query”: { “match”: { “field”: “value” } } } match_phrase&#xff1a;精确匹配短语&#xff0c;适合用于短语搜索。 { “query”: { “match_phrase”: { “field”: “text” }…...

SpringCloud系列教程:微服务的未来(十四)网关登录校验、自定义过滤器GlobalFilter、GatawayFilter

前言 在微服务架构中&#xff0c;API 网关扮演着至关重要的角色&#xff0c;负责路由请求、执行安全验证、流量控制等任务。Spring Cloud Gateway 作为一个强大的网关解决方案&#xff0c;提供了灵活的方式来实现这些功能。 本篇博客将重点介绍如何在 Spring Cloud Gateway 中…...

Android Studio:Linux环境下安装与配置

更多内容&#xff1a;XiaoJ的知识星球 Android Studio&#xff1a;Linux环境下安装与配置 1.安装JDK2.安装Android Studio2.1 获取安装包2.2 安装&#xff08;1&#xff09;配置环境变量&#xff1a;&#xff08;2&#xff09;运行安装&#xff1a;&#xff08;3&#xff09;配…...

使用AI生成金融时间序列数据:解决股市场的数据稀缺问题并提升信噪比

“GENERATIVE MODELS FOR FINANCIAL TIME SERIES DATA: ENHANCING SIGNAL-TO-NOISE RATIO AND ADDRESSING DATA SCARCITY IN A-SHARE MARKET” 论文地址&#xff1a;https://arxiv.org/pdf/2501.00063 摘要 金融领域面临的数据稀缺与低信噪比问题&#xff0c;限制了深度学习在…...

【银河麒麟高级服务器操作系统】业务访问慢网卡丢包现象分析及处理过程

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;product.kylinos.cn 开发者专区&#xff1a;developer.kylinos.cn 文档中心&#xff1a;document.kylinos.cn 交流论坛&#xff1a;forum.kylinos.cn 服务器环境以及配置 【内核版本…...