一 ,基本操作
1.0 前置操作
- 创建一个SpringBoot项目, maven引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.qcby</groupId><artifactId>MyBatisPlus</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.7</version><relativePath/> <!-- lookup parent from repository --></parent><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version><scope>runtime</scope></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--devtools热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><version>2.7.12</version><optional>true</optional></dependency></dependencies>
</project>
- 创建数据库mybatisplus_test,并创建t_user表
/*Navicat Premium Data TransferSource Server : localSource Server Type : MySQLSource Server Version : 80037Source Host : localhost:3306Source Schema : mybatisplus_testTarget Server Type : MySQLTarget Server Version : 80037File Encoding : 65001Date: 15/01/2025 19:07:56
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (`id` int NOT NULL AUTO_INCREMENT,`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`nick_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`user_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`age` int NOT NULL,`sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '1-男,0-女',`isDeleted` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, 'zhangsan', '1111111', '张三', '北京', 11, '1', '0');
INSERT INTO `t_user` VALUES (2, 'lisi', '1111111', '李四', '上海', 20, '0', '0');
INSERT INTO `t_user` VALUES (3, 'wangwu', '1111111', '王五', '广州', 34, '1', '0');
INSERT INTO `t_user` VALUES (4, 'zhaoliu', '1111111', '赵六', '深圳', 18, '1', '0');
INSERT INTO `t_user` VALUES (5, 'qianqi', '1111111', '钱七', '郑州', 3, '0', '0');SET FOREIGN_KEY_CHECKS = 1;
- 创建User类
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@TableName("t_user")
public class User {private Integer id;private String username;private String password;private Integer age;private Integer sex;private String nickName;
}
1.1 常用注解
1.1.1 @TableName
该注解用于指定实体类对应的数据库表名。当实体类名与数据库表名不一致,或者实体类名不是数据库表名的驼峰写法时,您需要使用这个注解来明确指定表名。
@TableName("t_user")
public class User {private Long id;private String name;private Integer age;private String email;
}
@TableName注解的属性
value: 用户自定义表名,默认值""
schema:数据库名称,除非数据库使用了schema,否则不写
keepGlobalPrefix:此实体类映射的表是否使用在配置文件指定全局的tablePrefix,**默认值false,即默认不使用;
**如果设置为 true,即使注解中指定了表名,也会自动加上全局的表前缀。
resultMap:指定在 XML 中定义的 ResultMap 的 ID,用于将查询结果映射到特定类型的实体类对象。
autoResultMap:是否自动构建 resultMap。如果已经设置了 resultMap,这个属性不会生效。
关于MyBatis的typeHandler,对于MyBatis-plus需要注意:
MyBatis 只支持将 typeHandler 写在两个地方:
1. 定义在 resultMap 中,作用于查询结果的封装。
2. 定义在 insert 和 update 语句的 #{property} 中的 property 后面,例如:#{property,typehandler=xxx.xxx.xxx},并且只作用于当前设置的值。
关于mybatis的typeHandler,这里有一篇博客:MyBatis之TypeHandler用法
excludeProperty:指定在映射时需要排除的属性名。这些属性将不会被包含在生成的 SQL 语句中。默认值String[];
这里的不会被包含在生成的sql中,指的是所有sql操作,只要涉及到了这个字段,都会被忽略
重点:与@TableField注解的exist区分
@TableId
该注解用于标记实体类中的主键字段。如果你的主键字段名为 id,你可以省略这个注解。
@TableName("sys_user")
public class User {@TableIdprivate Long id;private String name;private Integer age;private String email;
}
@TableId注解的属性
value:标记表的主键字段值,比如uid,id等
type:主键生成策略,**默认使用雪花算法**
IdType.AUTO
:使用数据库自增 ID 作为主键。
IdType.NONE
:无特定生成策略,如果全局配置中有 IdType 相关的配置,则会跟随全局配置。
IdType.INPUT
:在插入数据前,由用户自行设置主键值。
IdType.ASSIGN_ID
:自动分配 ID,适用于 Long、Integer、String 类型的主键。默认使用雪花算法通过 IdentifierGenerator 的 nextId 实现。@since 3.3.0
IdType.ASSIGN_UUID
:自动分配 UUID,适用于 String 类型的主键。默认实现为 IdentifierGenerator 的 nextUUID 方法。
@TableField
该注解用于标记实体类中的非主键字段,它告诉 MyBatis-Plus 如何映射实体类字段到数据库表字段。如果你的实体类字段名遵循驼峰命名规则,并且与数据库表字段名一致,你可以省略这个注解。
相当于我们用注解替代了*Mapper.xml中的resultMap!非常强大!
@TableField的属性
value
:指定数据库中的字段名。如果你的实体类字段名与数据库字段名不同,使用这个属性来指定正确的数据库字段名。
exist
:指示这个字段是否存在于数据库表中。如果设置为 false,MyBatis-Plus 在生成 SQL 时会忽略这个字段。
condition
:构建queryWrapper的时候,其中一个构造方法是传入一个实体,此时标注在实体字段上的注解就会生效,构建查询条件
实体类
@TableName("sys_user")
public class User {@TableIdprivate Long id;private String name;@TableField(condition = "%s > #{%s}") // 自定义 age 字段的条件表达式private Integer age;private String email;
}
查询
User queryEntity = new User();queryEntity.setAge(18); // 设置 age 字段的值// 创建 QueryWrapper 实例,并传递 User 实例QueryWrapper<User> queryWrapper = new QueryWrapper<>(queryEntity);// 执行查询List<User> userList = userMapper.selectList(queryWrapper);return userList;
update
:在执行更新操作时,指定字段在 SET 子句中的表达式。这个属性的优先级高于 el 属性,
允许你自定义字段的更新逻辑。
注意:el 属性允许你使用表达式来动态控制字段的更新行为,它使用的是 OGNL 表达式。 例如,你可以使用 @TableField(el = "CASE WHEN age > 18 THEN 'adult' ELSE 'child' END") 这样的表达式,在更新操作时根据一定的条件来计算字段的值。
@TableName("sys_user")
public class User {@TableIdprivate Long id;private String name;private Integer age;private String email;@TableField(update="%s+1") // 自定义更新时的表达式private Integer version;
}
会自动执行如下sql
UPDATE sys_user
SET name = 'Updated Name', age = 30, email = 'updated@example.com', version = version + 1
WHERE id = 1;
FieldStrategy 枚举类型定义:
insertStrategy:定义在插入新记录时,如何处理字段的值。这个属性允许你控制字段是否应该包含在 INSERT 语句中,以及在什么条件下包含。
FieldStrategy 枚举类型定义
FieldStrategy.DEFAULT:遵循全局配置的策略。如果全局配置未指定,默认行为是仅在字段值不为 NULL 时插入该字段。
FieldStrategy.ALWAYS:总是插入该字段,无论字段值是否为 NULL。
FieldStrategy.NOT_NULL:仅在字段值不为 NULL 时插入该字段。
FieldStrategy.NOT_EMPTY:仅在字段值不为空(对于字符串类型)或不为 NULL(对于其他类型)时插入该字段。
FieldStrategy.NEVER:从不插入该字段,即使字段值不为 NULL。
updateStrategy
:定义在更新记录时,如何处理字段的值。这个属性允许你控制字段是否应该包含在 UPDATE 语句的 SET 子句中,以及在什么条件下包含。
取值和insertStrategy 属性的FieldStrategy 枚举相同,这里不在赘述
whereStrategy
:定义在生成**更新语句的 WHERE 子句**
时,如何处理字段的值。这个属性允许你控制字段是否应该包含在 WHERE 子句中,以及在什么条件下包含。
取值和insertStrategy 属性的FieldStrategy 枚举相同,这里不在赘述
fill
:字段自动填充策略。该属性用于指定在执行数据库操作(如插入、更新)时,如何自动填充字段的值。通过使用 FieldFill 枚举,可以灵活地控制字段的填充行为。
此功能需要配合自动填充字段功能一起使用。也就是说项目中需要有自定义类实现MetaObjectHandler接口
FieldFill 枚举类型定义
FieldFill.DEFAULT:默认不进行填充,依赖于数据库的默认值或手动设置。
FieldFill.INSERT:在插入操作时自动填充字段值。
FieldFill.UPDATE:在更新操作时自动填充字段值。
FieldFill.INSERT_UPDATE:在插入和更新操作时都会自动填充字段值。
select
:指示在执行查询操作时,该字段是否应该包含在 SELECT 语句中。这个属性允许您控制查询结果中包含哪些字段,从而提供更细粒度的数据访问控制。
与exist属性的区别在于,exist会在所有生成的sql所有可能出现字段的位置中忽略这个字段,select属性只会忽略select的查询结果中的这个字段
@TableName("user")
public class User {// 其他字段...@TableField(select = false)private String password;// 构造函数、getter 和 setter...
}
keepGlobalFormat
:
默认false
指示在处理字段时是否保持使用全局 DbConfig 中定义的 columnFormat 规则。这个属性用于控制字段值在数据库操作中是否应用全局的列格式化规则。
jdbcType
:JDBC类型,用于指定字段在数据库中的数据类型。这个属性允许您显式地设置字段的数据库类型,以确保与数据库的兼容性,特别是在处理特殊类型或自定义类型时。
详细说明
当 jdbcType 属性设置为 JdbcType.UNDEFINED(默认值)时,MyBatis-Plus 将根据字段的 Java 类型自动推断其 JDBC 类型。
当 jdbcType 属性设置为特定的 JdbcType 枚举值时,该字段将使用指定的 JDBC 类型进行数据库操作。这可以用于解决类型映射问题,或者在需要精确控制数据库类型时使用。
一般不用显示设置这个值,MyBatisPlus可以自动处理类型一年干涉。除非想主动转换类型,比如把User类转为Varchar存入数据库
typeHandler
:类型处理器,用于指定在数据库操作中如何处理特定字段的值。这个属性允许您自定义字段值的转换逻辑,以适应特定的数据类型或业务需求。
详细说明
当 typeHandler 属性未设置(即使用默认值 UnknownTypeHandler.class)时,MyBatis-Plus 将使用默认的类型处理器来处理字段值。
当 typeHandler 属性设置为特定的 TypeHandler 子类时,该字段将使用指定的类型处理器进行数据库操作。这可以用于处理自定义类型、特殊数据格式或非标准的数据库类型。
numericScale
:指定小数点后保留的位数,该属性仅在执行 update 操作时生效。它用于控制数值类型字段在更新时的小数精度。
详细说明
当 numericScale 属性设置为空字符串(默认值)时,字段的小数精度将遵循数据库的默认设置或字段定义时的设置。
当 numericScale 属性设置为特定的数值(如 “2”)时,该字段在执行 update 操作时将按照指定的小数位数进行处理。
@Version注解
该注解用于标记实体类中的字段作为乐观锁版本号字段。
乐观锁是一种并发控制机制,它假设多个事务可以同时进行而不会互相干扰,只在提交事务时检查是否有冲突。通过在实体类中使用@Version注解,MyBatis-Plus 会在更新操作时自动检查版本号,确保在更新过程中数据没有被其他事务修改。
@EnumValue
该注解用于标记枚举类中的字段,指定在数据库中存储的枚举值。当实体类中的某个字段是枚举类型时,使用@EnumValue注解可以告诉MyBatis-Plus在数据库中存储枚举值的哪个属性。
这个注解不需要标注在实体类的字段上,而是标注在Enum类的get方法上
@TableName("sys_user")
public class User {@TableIdprivate Long id;@TableField("nickname") // 映射到数据库字段 "nickname"private String name;private Integer age;private String email;private Gender gender; // 假设 Gender 是一个枚举类型
}public enum Gender {MALE("M", "男"),FEMALE("F", "女");private String code;private String description;Gender(String code, String description) {this.code = code;this.description = description;}@EnumValue // 指定存储到数据库的枚举值为 codepublic String getCode() {return code;}
}
@TableLogic
该注解用于标记实体类中的字段作为逻辑删除字段。逻辑删除是一种数据管理策略,它不是真正地从数据库中删除记录,而是在记录中标记该记录为已删除状态。通过使用@TableLogic注解,MyBatis-Plus 可以在查询、更新和删除操作中自动处理逻辑删除字段的值。
@KeySequence
该注解用于指定 Oracle 数据库中序列(Sequence)的名称,以便在实体类中生成主键值。在 Oracle 数据库中,主键通常是通过序列来生成的,而不是像其他数据库那样使用自增字段。@KeySequence注解告诉 MyBatis-Plus 使用特定的序列来生成主键。
@InterceptorIgnore
该注解用于指定Mapper的某个method(注解在method上)或者所有method(注解在Mapper上)在执行时是否忽略特定的插件(比如多租户)
// @InterceptorIgnore(tenantLine = "1") // 忽略多租户拦截器
public interface UserMapper extends BaseMapper<User> {@InterceptorIgnore(tenantLine = "1") // 忽略多租户拦截器List<User> selectUsers();
}
@OrderBy
该注解用于指定实体类中的字段在执行查询操作时的默认排序方式。通过在实体类字段上使用@OrderBy注解,可以确保在执行查询时,如果没有显式指定排序条件,MyBatis-Plus 将按照注解中定义的排序规则返回结果。
@TableName("sys_user")
public class User {@TableIdprivate Long id;@TableField("nickname") // 映射到数据库字段 "nickname"private String name;@OrderBy(asc = false, sort = 10) // 指定默认排序为倒序,优先级为10private Integer age;private String email;
}
需要注意的是,@OrderBy注解的排序规则优先级低于在查询时通过Wrapper条件查询对象显式指定的排序条件。如果在Wrapper中指定了排序条件,那么@OrderBy注解中定义的默认排序将被覆盖。
1.2 BaseMapper方法
package com.qcby.myBatisPlus;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qcby.myBatisPlus.entity.User;
import com.qcby.myBatisPlus.enums.SexEnum;
import com.qcby.myBatisPlus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.sql.Timestamp;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@SpringBootTest
public class MyBatisPlusTest {@Autowiredprivate UserMapper userMapper;// 测试插入方法@Testpublic void testInsert() {// 创建一个新的 User 对象User user = new User("zxk", "222222", "末影猫", "河北", 26,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);// 调用 userMapper 的 insert 方法将用户信息插入数据库int result = userMapper.insert(user);System.out.println("受影响行数:" + result);// 插入成功后,MyBatis-Plus 会自动为自增主键赋值,可以通过 user.getId() 获取插入后的主键值System.out.println("id 自动获取:" + user.getId());}// 测试根据 id 删除用户信息的方法@Testpublic void testDeleteById() {// 通过主键 id 删除用户信息// DELETE FROM user WHERE id =?// 这里的 id 必须是一个实现了 Serializable 接口的对象int result = userMapper.deleteById(1881023900211396610L);System.out.println("受影响行数:" + result);}// 测试根据实体对象的 id 删除用户信息的方法@Testpublic void testDeleteById2() {// 通过 id 删除用户信息,这里使用了 User 对象// DELETE FROM user WHERE id =?// 这里的 id 必须是一个实现了 Serializable 接口的对象User user = new User();user.setId(1L);int result = userMapper.deleteById(user);System.out.println("受影响行数:" + result);}// 测试根据 Map 中的条件删除记录的方法@Testpublic void testDeleteByMap() {// 根据 Map 集合中所设置的条件删除记录// DELETE FROM user WHERE name =? AND age =?// Map 中的元素之间是 AND 关系Map<String, Object> map = new HashMap<>();map.put("age", 23);map.put("username", "末影猫");int result = userMapper.deleteByMap(map);System.out.println("受影响行数:" + result);}// 测试批量删除多个 id 的方法@Testpublic void testDeleteBatchIds() {// 通过多个 id 批量删除// DELETE FROM user WHERE id IN (?,?,?)List<Long> idList = Arrays.asList(1L, 2L, 3L);int result = userMapper.deleteBatchIds(idList);System.out.println("受影响行数:" + result);}// 测试根据 id 更新用户信息的方法@Testpublic void testUpdateById() {// 创建一个更新后的 User 对象User user = new User();user.setId(11L);// UPDATE user SET name =?, age =? WHERE id =?int result = userMapper.updateById(user);System.out.println("受影响行数:" + result);}// 测试更新用户信息的方法@Testpublic void testUpdate() {// 创建一个更新后的 User 对象User user = new User("zxk2", "111111", "末影猫2", "东北", 62,SexEnum.FEMALE, new Timestamp(System.currentTimeMillis()), false);// 可以使用 QueryWrapper 来设置更新条件QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 23); // 例如,只更新 age 为 23 的用户信息// UPDATE user SET name =?, age =? WHERE age = 23int result = userMapper.update(user, queryWrapper);System.out.println("受影响行数:" + result);}// 测试根据 id 查询用户信息的方法@Testpublic void testSelectById() {// 通过主键 id 查询用户信息// SELECT * FROM user WHERE id =?Long userId = 1L;User user = userMapper.selectById(userId);System.out.println(user);}// 测试批量查询用户信息的方法@Testpublic void testSelectBatchIds() {// 通过多个 id 批量查询用户信息// SELECT * FROM user WHERE id IN (?,?,?)List<Long> idList = Arrays.asList(1L, 2L, 3L);List<User> userList = userMapper.selectBatchIds(idList);for (User user : userList) {System.out.println(user);}}// 测试根据条件查询用户信息的方法@Testpublic void testSelectOne() {// 查询符合条件的单个用户信息// 本质上为调用 selectList 后,返回第一条(结果多余 1 条会报错)QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 23); // 例如,查询 age 为 23 的用户信息User user = userMapper.selectOne(queryWrapper);System.out.println(user);}// 测试判断是否存在满足条件的用户信息的方法@Testpublic void testExists() {// 调用 selectCount,count > 0 即返回 true,反之则 falseQueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 23); // 例如,判断是否存在 age 为 23 的用户boolean exists = userMapper.exists(queryWrapper);System.out.println(exists);}// 测试统计满足条件的用户数量的方法@Testpublic void testSelectCount() {// 统计满足条件的用户数量QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 23); // 例如,统计 age 为 23 的用户数量Long count = userMapper.selectCount(queryWrapper);System.out.println(count);}// 测试查询满足条件的用户列表的方法@Testpublic void testSelectList() {// 查询满足条件的用户列表QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 23); // 例如,查询 age 为 23 的用户列表List<User> userList = userMapper.selectList(queryWrapper);for (User user : userList) {System.out.println(user);}}// 测试查询满足条件的用户列表,并将结果以 Map 形式返回的方法@Testpublic void testSelectMaps() {// 查询满足条件的用户列表,并将结果以 Map 形式返回QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 23); // 例如,查询 age 为 23 的用户列表,并以 Map 形式返回List<Map<String, Object>> userMapList = userMapper.selectMaps(queryWrapper);for (Map<String, Object> userMap : userMapList) {System.out.println(userMap);}}// 测试查询满足条件的用户列表,并将结果以对象列表形式返回的方法@Testpublic void testSelectObjs() {// 查询满足条件的用户列表,并将结果以对象列表形式返回QueryWrapper<User> queryWrapper = new QueryWrapper<>();List<Object> userObjList = userMapper.selectObjs(queryWrapper);for (Object userObj : userObjList) {System.out.println(userObj);}}// 测试分页查询用户信息的方法@Testpublic void testSelectPage() {// 进行分页查询// 这里设置分页参数,第一页,每页显示 5 条记录IPage<User> page = new Page<>(1, 5);QueryWrapper<User> queryWrapper = new QueryWrapper<>();IPage<User> userPage = userMapper.selectPage(page, queryWrapper);System.out.println("总页数:" + userPage.getPages());System.out.println("总记录数:" + userPage.getTotal());for (User user : userPage.getRecords()) {System.out.println(user);}}// 测试分页查询用户信息,并将结果以 Map 形式返回的方法@Testpublic void testSelectMapsPage() {// 进行分页查询,并将结果以 Map 形式返回// 这里设置分页参数,第一页,每页显示 5 条记录IPage<Map<String, Object>> page = new Page<>(1, 5);QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 23); // 例如,查询 age 为 23 的用户信息,并进行分页,结果以 Map 形式返回IPage<Map<String, Object>> userMapPage = userMapper.selectMapsPage(page, queryWrapper);System.out.println("总页数:" + userMapPage.getPages());System.out.println("总记录数:" + userMapPage.getTotal());for (Map<String, Object> userMap : userMapPage.getRecords()) {System.out.println(userMap);}}
}
1.3 BaseService方法
package com.qcby.myBatisPlus;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qcby.myBatisPlus.entity.User;
import com.qcby.myBatisPlus.enums.SexEnum;
import com.qcby.myBatisPlus.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.sql.Timestamp;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@SpringBootTest
public class MyBatisPlusTest2 {@Autowiredprivate UserService userService; // 假设 UserService 是实现了 IService<User> 的服务类// 测试 save 方法:保存一个新的实体对象@Testpublic void testSave() {User user = new User("Don Quixote", "333333", "堂吉诃德", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);boolean result = userService.save(user);System.out.println("保存操作结果:" + result);// 打印插入后的主键System.out.println("插入后的主键:" + user.getId());}// 测试 saveBatch 方法:批量保存实体对象@Testpublic void testSaveBatch() {User user1 = new User("Don Quixote2", "333333", "堂吉诃德2", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user2 = new User("Don Quixote3", "333333", "堂吉诃德3", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user3 = new User("Don Quixote4", "333333", "堂吉诃德4", "外国", 65,SexEnum.FEMALE, new Timestamp(System.currentTimeMillis()), false);boolean result = userService.saveBatch(Arrays.asList(user1, user2, user3));System.out.println("批量保存操作结果:" + result);// 打印插入后的主键System.out.println("插入后的主键 1:" + user1.getId());System.out.println("插入后的主键 2:" + user2.getId());System.out.println("插入后的主键 3:" + user3.getId());}// 测试 saveBatch 方法:批量保存实体对象,并设置批量大小@Testpublic void testSaveBatchWithBatchSize() {User user1 = new User("Don Quixote10", "333333", "堂吉诃德10", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user2 = new User("Don Quixote20", "333333", "堂吉诃德20", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user3 = new User("Don Quixote30", "333333", "堂吉诃德30", "外国", 65,SexEnum.FEMALE, new Timestamp(System.currentTimeMillis()), false);boolean result = userService.saveBatch(Arrays.asList(user1, user2, user3), 2);System.out.println("批量保存操作结果:" + result);// 打印插入后的主键System.out.println("插入后的主键 1:" + user1.getId());System.out.println("插入后的主键 2:" + user2.getId());System.out.println("插入后的主键 3:" + user3.getId());}// 测试 saveOrUpdate 方法:保存或更新实体对象@Testpublic void testSaveOrUpdate() {User user = new User("Don Quixote10", "333333", "堂吉诃德10", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);boolean result = userService.saveOrUpdate(user);System.out.println("保存或更新操作结果:" + result);}// 测试 saveOrUpdateBatch 方法:批量保存或更新实体对象@Testpublic void testSaveOrUpdateBatch() {User user1 = new User("Don Quixote10", "333333", "堂吉诃德10", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user2 = new User("Don Quixote20", "333333", "堂吉诃德20", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user3 = new User("Don Quixote30", "333333", "堂吉诃德30", "外国", 65,SexEnum.FEMALE, new Timestamp(System.currentTimeMillis()), false);boolean result = userService.saveOrUpdateBatch(Arrays.asList(user1, user2, user3));System.out.println("批量保存或更新操作结果:" + result);}// 测试 saveOrUpdateBatch 方法:批量保存或更新实体对象,并设置批量大小@Testpublic void testSaveOrUpdateBatchWithBatchSize() {User user1 = new User("Don Quixote10", "333333", "堂吉诃德10", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user2 = new User("Don Quixote20", "333333", "堂吉诃德20", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user3 = new User("Don Quixote30", "333333", "堂吉诃德30", "外国", 65,SexEnum.FEMALE, new Timestamp(System.currentTimeMillis()), false);boolean result = userService.saveOrUpdateBatch(Arrays.asList(user1, user2, user3), 2);System.out.println("批量保存或更新操作结果:" + result);}// 测试 removeById 方法:根据 ID 删除实体对象@Testpublic void testRemoveById() {boolean result = userService.removeById(1L);System.out.println("根据 ID 删除操作结果:" + result);}// 测试 removeById 方法:根据实体对象的 ID 删除实体对象@Testpublic void testRemoveByIdEntity() {User user = new User();user.setId(2L);boolean result = userService.removeById(user);System.out.println("根据实体对象的 ID 删除操作结果:" + result);}// 测试 removeByMap 方法:根据条件映射删除实体对象@Testpublic void testRemoveByMap() {Map<String, Object> columnMap = new HashMap<>();columnMap.put("age", 25);boolean result = userService.removeByMap(columnMap);System.out.println("根据条件映射删除操作结果:" + result);}// 测试 remove 方法:根据条件删除实体对象@Testpublic void testRemove() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 26);boolean result = userService.remove(queryWrapper);System.out.println("根据条件删除操作结果:" + result);}// 测试 removeByIds 方法:根据多个 ID 批量删除实体对象@Testpublic void testRemoveByIds() {boolean result = userService.removeByIds(Arrays.asList(1L, 2L, 3L));System.out.println("根据多个 ID 批量删除操作结果:" + result);}// 测试 removeBatchByIds 方法:根据多个 ID 批量删除实体对象,并设置批量大小@Testpublic void testRemoveBatchByIds() {boolean result = userService.removeBatchByIds(Arrays.asList(1L, 2L, 3L), 2);System.out.println("根据多个 ID 批量删除操作结果:" + result);}// 测试 updateById 方法:根据 ID 更新实体对象@Testpublic void testUpdateById() {User user = new User("Don Quixote10", "333333", "堂吉诃德10", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);boolean result = userService.updateById(user);System.out.println("根据 ID 更新操作结果:" + result);}// 测试 update 方法:根据条件更新实体对象@Testpublic void testUpdate() {User user = new User("Don Quixote10", "333333", "堂吉诃德10", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.eq("age", 25);boolean result = userService.update(user, updateWrapper);System.out.println("根据条件更新操作结果:" + result);}// 测试 updateBatchById 方法:根据 ID 批量更新实体对象@Testpublic void testUpdateBatchById() {User user1 = new User("Don Quixote10", "333333", "堂吉诃德10", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user2 = new User("Don Quixote20", "333333", "堂吉诃德20", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user3 = new User("Don Quixote30", "333333", "堂吉诃德30", "外国", 65,SexEnum.FEMALE, new Timestamp(System.currentTimeMillis()), false);boolean result = userService.updateBatchById(Arrays.asList(user1, user2, user3));System.out.println("根据 ID 批量更新操作结果:" + result);}// 测试 updateBatchById 方法:根据 ID 批量更新实体对象,并设置批量大小@Testpublic void testUpdateBatchByIdWithBatchSize() {User user1 = new User("Don Quixote10", "333333", "堂吉诃德10", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user2 = new User("Don Quixote20", "333333", "堂吉诃德20", "外国", 65,SexEnum.MALE, new Timestamp(System.currentTimeMillis()), false);User user3 = new User("Don Quixote30", "333333", "堂吉诃德30", "外国", 65,SexEnum.FEMALE, new Timestamp(System.currentTimeMillis()), false);boolean result = userService.updateBatchById(Arrays.asList(user1, user2, user3), 2);System.out.println("根据 ID 批量更新操作结果:" + result);}// 测试 getById 方法:根据 ID 获取实体对象@Testpublic void testGetById() {User user = userService.getById(1L);System.out.println("根据 ID 获取的实体对象:" + user);}// 测试 listByIds 方法:根据多个 ID 获取实体对象列表@Testpublic void testListByIds() {List<User> users = userService.listByIds(Arrays.asList(1L, 2L, 3L));for (User user : users) {System.out.println("根据多个 ID 获取的实体对象:" + user);}}// 测试 listByMap 方法:根据条件映射获取实体对象列表@Testpublic void testListByMap() {Map<String, Object> columnMap = new HashMap<>();columnMap.put("age", 25);List<User> users = userService.listByMap(columnMap);for (User user : users) {System.out.println("根据条件映射获取的实体对象:" + user);}}// 测试 getOne 方法:根据条件获取单个实体对象@Testpublic void testGetOne() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);User user = userService.getOne(queryWrapper);System.out.println("根据条件获取的单个实体对象:" + user);}// 测试 getOne 方法:根据条件获取单个实体对象,并设置是否抛出异常@Testpublic void testGetOneWithThrowEx() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);User user = userService.getOne(queryWrapper, false);System.out.println("根据条件获取的单个实体对象:" + user);}// 测试 getMap 方法:根据条件获取实体对象的映射@Testpublic void testGetMap() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 65);Map<String, Object> userMap = userService.getMap(queryWrapper);System.out.println("根据条件获取的实体对象映射:" + userMap);}// 测试 getObj 方法:根据条件获取对象,并应用映射函数@Testpublic void testGetObj() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);Object obj = userService.getObj(queryWrapper, o -> ((User) o).getUsername());System.out.println("根据条件获取的对象:" + obj);}// 测试 count 方法:统计满足条件的实体对象数量@Testpublic void testCount() {long count = userService.count();System.out.println("满足条件的实体对象数量:" + count);}// 测试 count 方法:根据条件统计实体对象数量@Testpublic void testCountWithWrapper() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);long count = userService.count(queryWrapper);System.out.println("根据条件统计的实体对象数量:" + count);}// 测试 list 方法:根据条件获取实体对象列表@Testpublic void testList() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);List<User> users = userService.list(queryWrapper);for (User user : users) {System.out.println("根据条件获取的实体对象列表:" + user);}}// 测试 list 方法:获取所有实体对象列表@Testpublic void testListAll() {List<User> users = userService.list();for (User user : users) {System.out.println("获取的所有实体对象列表:" + user);}}// 测试 page 方法:根据条件分页获取实体对象列表@Testpublic void testPage() {IPage<User> page = new Page<>(1, 2);QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);IPage<User> resultPage = userService.page(page, queryWrapper);System.out.println("总页数:" + resultPage.getPages());System.out.println("总记录数:" + resultPage.getTotal());for (User user : resultPage.getRecords()) {System.out.println("分页获取的实体对象:" + user);}}// 测试 page 方法:分页获取所有实体对象列表@Testpublic void testPageAll() {IPage<User> page = new Page<>(1, 2);IPage<User> resultPage = userService.page(page);System.out.println("总页数:" + resultPage.getPages());System.out.println("总记录数:" + resultPage.getTotal());for (User user : resultPage.getRecords()) {System.out.println("分页获取的所有实体对象:" + user);}}// 测试 listMaps 方法:根据条件获取实体对象映射列表@Testpublic void testListMaps() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);List<Map<String, Object>> userMaps = userService.listMaps(queryWrapper);for (Map<String, Object> userMap : userMaps) {System.out.println("根据条件获取的实体对象映射列表:" + userMap);}}// 测试 listMaps 方法:获取所有实体对象映射列表@Testpublic void testListMapsAll() {List<Map<String, Object>> userMaps = userService.listMaps();for (Map<String, Object> userMap : userMaps) {System.out.println("获取的所有实体对象映射列表:" + userMap);}}// 测试 listObjs 方法:根据条件获取对象列表@Testpublic void testListObjs() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);List<Object> objs = userService.listObjs(queryWrapper);for (Object obj : objs) {System.out.println("根据条件获取的对象列表:" + obj);}}// 测试 listObjs 方法:根据条件获取对象列表,并应用映射函数@Testpublic void testListObjsWithMapper() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);List<String> names = userService.listObjs(queryWrapper, o -> ((User) o).getNickName());for (String name : names) {System.out.println("根据条件获取的对象列表(映射后):" + name);}}// 测试 pageMaps 方法:根据条件分页获取实体对象映射列表@Testpublic void testPageMaps() {IPage<Map<String, Object>> page = new Page<>(1, 2);QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 25);IPage<Map<String, Object>> resultPage = userService.pageMaps(page, queryWrapper);System.out.println("总页数:" + resultPage.getPages());System.out.println("总记录数:" + resultPage.getTotal());for (Map<String, Object> userMap : resultPage.getRecords()) {System.out.println("分页获取的实体对象映射:" + userMap);}}// 测试 pageMaps 方法:分页获取所有实体对象映射列表@Testpublic void testPageMapsAll() {IPage<Map<String, Object>> page = new Page<>(1, 2);IPage<Map<String, Object>> resultPage = userService.pageMaps(page);System.out.println("总页数:" + resultPage.getPages());System.out.println("总记录数:" + resultPage.getTotal());for (Map<String, Object> userMap : resultPage.getRecords()) {System.out.println("分页获取的所有实体对象映射:" + userMap);}}// 测试 query 方法:使用 QueryChainWrapper 进行链式查询@Testpublic void testQuery() {QueryChainWrapper<User> queryChainWrapper = userService.query();List<User> users = queryChainWrapper.eq("age", 25).list();for (User user : users) {System.out.println("通过 QueryChainWrapper 查询的实体对象:" + user);}}// 测试 lambdaQuery 方法:使用 LambdaQueryChainWrapper 进行链式查询@Testpublic void testLambdaQuery() {LambdaQueryChainWrapper<User> lambdaQueryChainWrapper = userService.lambdaQuery();List<User> users = lambdaQueryChainWrapper.eq(User::getAge, 25).list();for (User user : users) {System.out.println("通过 LambdaQueryChainWrapper 查询的实体对象:" + user);}}// 测试 ktQuery 方法:使用 KtQueryChainWrapper 进行链式查询(假设使用 Kotlin)@Testpublic void testKtQuery() {// 这里假设你在 Kotlin 环境中使用,以下代码仅为示意,需要根据实际情况调整// KtQueryChainWrapper<User> ktQueryChainWrapper = userService.ktQuery();// List<User> users = ktQueryChainWrapper.eq(User::getAge, 25).list();// for (User user : users) {// System.out.println("通过 KtQueryChainWrapper 查询的实体对象:" + user);// }System.out.println("请在 Kotlin 环境中测试 KtQueryChainWrapper");}// 测试 update 方法:使用 UpdateChainWrapper 进行链式更新@Testpublic void testUpdateChain() {UpdateChainWrapper<User> updateChainWrapper = userService.update();boolean result = updateChainWrapper.eq("age", 25).set("age", 26).update();System.out.println("通过 UpdateChainWrapper 更新的结果:" + result);}// 测试 lambdaUpdate 方法:使用 LambdaUpdateChainWrapper 进行链式更新@Testpublic void testLambdaUpdate() {LambdaUpdateChainWrapper<User> lambdaUpdateChainWrapper = userService.lambdaUpdate();boolean result = lambdaUpdateChainWrapper.eq(User::getAge, 25).set(User::getAge, 26).update();System.out.println("通过 LambdaUpdateChainWrapper 更新的结果:" + result);}// 测试 ktUpdate 方法:使用 KtUpdateChainWrapper 进行链式更新(假设使用 Kotlin)@Testpublic void testKtUpdate() {// 这里假设你在 Kotlin 环境中使用,以下代码仅为示意,需要根据实际情况调整// KtUpdateChainWrapper<User> ktUpdateChainWrapper = userService.ktUpdate();// boolean result = ktUpdateChainWrapper.eq(User::getAge, 25).set(User::getAge, 26).update();// System.out.println("通过 KtUpdateChainWrapper 更新的结果:" + result);System.out.println("请在 Kotlin 环境中测试 KtUpdateChainWrapper");}
}
二,MyBatisPlus插件
通过拦截器实现
@Configuration
@MapperScan("com.qcby.myBatisPlus.mapper")
public class MyBatisPlusConfig {/*** 添加分页插件(如果配置多个插件, 切记分页最后添加)*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());// 乐观锁插件PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);paginationInnerInterceptor.setDialect(new MySqlDialect());
// paginationInnerInterceptor.setMaxLimit(5000L);
// paginationInnerInterceptor.setOverflow(true);interceptor.addInnerInterceptor(paginationInnerInterceptor); // 分页插件return interceptor;}
}