一、条件构造器函数列表
函数名 | 说明 | 说明/例子 |
---|---|---|
allEq | 入参都满足条件 | 例:allEq({"id": 1, "name": "张三", "age": null})--->id = 1 and name = '张三' and age is null |
eq | 等于= | 例:eq("name", "张三") ---> name = '张三' |
ne | 不等于<> | 例:ne("name", "张三") ---> name <> '张三' |
gt | 大于> | 例:gt("age", 18) ---> age > 18 |
ge | 大于等于>= | 例:ge("age", 18) ---> age >= 18 |
lt | 小于< | 例:lt("age", 18) ---> age < 18 |
le | 小于等于<= | 例:le("age", 18) ---> age <= 18 |
between | between 值1 and 值2 | 例:between("age", 18, 30) ---> age between 18 and 30 |
notBetween | not between 值1 and 值2 | 例:notBetween("age", 18, 30) ---> age not between 18 and 30 |
like | like '%值%' | 例:like("name", "张") ---> name like '%张%' |
notLike | not like '%值%' | 例:notLike("name", "张") ---> name not like '%张%' |
likeLeft | like '%值' | 例:likeLeft("name", "张") ---> name like '%张' |
likeRight | like '值%' | 例:likeRight("name", "张") ---> name like '张%' |
notLikeLeft | not like '%值' | 例:notLikeLeft("name", "张") ---> name not like '%张' |
notLikeRight | not like '值%' | 例:notLikeRight("name", "张") ---> name not like '张' |
isNull | 字段 is null | 例:isNull("name") ---> name is null |
isNotNull | 字段 is not null | 例:isNotNull("name") ---> name is not null |
in | 字段 in (v0, v1, ...) | 例:in("age", {18, 19, 20}) ---> age in (18, 19, 20) |
notIn | 字段 not in (v0, v1, ...) | 例:notIn("age", {18, 19, 20}) ---> age not in (18, 19, 20) |
inSql | 字段 in ( sql语句 ) | 例:inSql("age", "select age from table where id < 3") ---> age in (select age from table where id < 3) |
notInSql | 字段 not in ( sql语句 ) | 例:notInSql("age", "select age from table where id < 3") ---> age not in (select age from table where id < 3) |
groupBy | 分组:group by 字段, ... | 例:groupBy("id", "name") ---> group by id, name |
orderByAsc | 排序:order by 字段, ... asc | 例:orderByAsc("id", "name") ---> order by id asc, name asc |
orderByDesc | 排序:order by 字段, ... desc | 例:orderByDesc("id", "name") ---> order by id desc, name desc |
orderBy | 排序:order by 字段, ... | 例:orderBy("id", "name") ---> order by id, name |
having | having ( sql 语句 ) | 例:having("sum(age) > {0}", 18) ---> having sum(age) > 18 |
func | func 方法(主要方便在出现 if...else 下调用不同方法能不断链) | 例:func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 2)}) |
or | 或者 | 注意: 主动调用or表示紧接着下一个方嘎不是用and连接!(不调用or则默认为使用and连接) 例:eq("id", 1).or.eq("name", "张三") ---> id = 1 or name = '张三' |
and | 并且 | 例:and(i -> i.eq("name", "张三").ne("status", "活着")) ---> and (name = '张三' and status != '活着') |
apply | 拼接 sql | 注意: 该方法可用于数据库函数,动态入参的params对应前面sqlHaving内部的{index}部分,这样是不会有sql注入风险的,反之则有! 例:apply("date_format(dateColumn, '%Y-%m-%d') = {0}", "2023-12-05") ---> date_format(dateColumn, '%Y-%m-%d') = '2023-12-05' |
last | 无视优化规则直接拼接到 sql 的最后 | 注意: 只能调用一次,多次调用以最后一次为准,有sql注入的风险! 例:last("limit 1") |
exists | 拼接 exists ( sql 语句 ) | 例:exists("select 1 from table where age = 18") ---> exists(select 1 from table where age = 18) |
notExists | 拼接 not exists ( sql 语句 ) | 例:notExists("select 1 from table where age = 18") ---> not exists (select 1 from table where age = 18) |
nested | 正常嵌套,不带 and 或者 or | 例:nested(i -> i.eq("name", "张三").ne("status", "活着")) ---> (name = '张三' and status != '活着') |
QueryWrapper | 继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取 | |
select | 设置查询字段 | 例1:select("id", "name", "age") 例2:select(i -> i.getProperty().startsWith("test")) |
UpdateWrapper | 继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件及 LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取 | |
set | 设置字段属性 | 例1:set("name", "老李头") 例1:set("name", "")--->数据库字段值变为空字符串 例3:set("name", null)--->数据库字段值变为null |
setSql | 设置部分sql | 例: setSql("name = '张三'") |
lambda | 获取 LambdaWrapper 在QueryWrapper中是获取LambdaQueryWrapper 在UpdateWrapper中是获取LambdaUpdateWrapper |
二、扩展
1. 逻辑删除
- 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
- 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。
- 使用方法:
- 配置删除默认值:
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
-
- 实体类字段上加上
@TableLogic
注解
- 实体类字段上加上
@TableLogic
private Integer deleted;
删除:update table set deleted = 1 where id = 1 and deleted = 0
查找:select id, name, deleted from table where deleted = 0
2. 通用枚举
- 声明通用枚举属性即可使用
方式一: 使用 @EnumValue
注解枚举属性
public enum GradeEnum {
PRIMARY(1, "小学"), SECONDORY(2, "中学"), HIGH(3, "高中");
GradeEnum(int code, String descp) {
this.code = code;
this.descp = descp;
}
@EnumValue//标记数据库存的值是code
private final int code;
//。。。
}
方式二: 枚举属性,实现 IEnum
接口如下:
public enum AgeEnum implements IEnum<Integer> {
ONE(1, "一岁"),
TWO(2, "二岁"),
THREE(3, "三岁");
private int value;
private String desc;
@Override
public Integer getValue() {
return this.value;
}
}
实体属性使用枚举类型
public class User {
/**
* 名字
* 数据库字段: name varchar(20)
*/
private String name;
/**
* 年龄,IEnum接口的枚举处理
* 数据库字段:age INT(3)
*/
private AgeEnum age;
/**
* 年级,原生枚举(带{@link com.baomidou.mybatisplus.annotation.EnumValue}):
* 数据库字段:grade INT(2)
*/
private GradeEnum grade;
}
3. 字段类型处理器
- 类型处理器,用于
JavaType
与JdbcType
之间的转换,用于PreparedStatement
设置参数值和从ResultSet
或CallableStatement
中取出一个值。 JSON
字段类型:
@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
private Long id;
...
/**
* 注意!! 必须开启映射注解
*
* @TableName(autoResultMap = true)
*
* 以下两种类型处理器,二选一 也可以同时存在
*
* 注意!!选择对应的 JSON 处理器也必须存在对应 JSON 解析依赖包
*/
@TableField(typeHandler = JacksonTypeHandler.class)
// @TableField(typeHandler = FastjsonTypeHandler.class)
private OtherInfo otherInfo;
}
4. 自动填充功能
原理:
- 实现元对象处理器接口:
com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
- 注解填充字段
@TableField(.. fill = FieldFill.INSERT)
生成器策略部分也可以配置!
public class User {
// 注意!这里需要标记为填充字段
@TableField(.. fill = FieldFill.INSERT)
private String createTime;
....
}
- 自定义实现类
MyMetaObjectHandler
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
// 或者
this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
// 或者
this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
}
FieldFill
的几种属性:
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入填充字段
*/
INSERT,
/**
* 更新填充字段
*/
UPDATE,
/**
* 插入和更新填充字段
*/
INSERT_UPDATE
}
5. SQL注入器
- 全局配置
sqlInjector
用于注入ISqlInjector
接口的子类,实现自定义方法注入。 - SQL 自动注入器接口
ISqlInjector
public interface ISqlInjector {
/**
* <p>
* 检查SQL是否注入(已经注入过不再注入)
* </p>
*
* @param builderAssistant mapper 信息
* @param mapperClass mapper 接口的 class 对象
*/
void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass);
}
自定义自己的通用方法可以实现接口 ISqlInjector
也可以继承抽象类 AbstractSqlInjector
注入通用方法 SQL 语句
然后继承 BaseMapper
添加自定义方法,全局配置 sqlInjector
注入 MP 会自动将类所有方法注入到 mybatis
容器中。
6. 数据安全保护
- 该功能为了保护数据库配置及数据安全,在一定的程度上控制开发人员流动导致敏感信息泄露。
配置安全:
- YML 配置:
// 加密配置 mpw: 开头紧接加密内容( 非数据库配置专用 YML 中其它配置也是可以使用的 )
spring:
datasource:
url: mpw:qRhvCwF4GOqjessEB3G+a5okP+uXXr96wcucn2Pev6Bf1oEMZ1gVpPPhdDmjQqoM
password: mpw:Hzy5iliJbwDHhjLs1L0j6w==
username: mpw:Xb+EgsyuYRXw7U7sBJjBpA==
- 密钥加密:
// 生成 16 位随机 AES 密钥
String randomKey = AES.generateRandomKey();
// 随机密钥加密
String result = AES.encrypt(data, randomKey);
- 使用:
// Jar 启动参数( idea 设置 Program arguments , 服务器可以设置为启动环境变量 )
--mpw.key=d1104d7c3b616f0b
7. 多数据源
- 多数据源既动态数据源,项目开发逐渐扩大,单个数据源、单一数据源已经无法满足需求项目的支撑需求。由此延伸了多数据源的扩展。
使用方法:
- 引入dynamic-datasource-spring-boot-starter
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${version}</version>
</dependency>
2. 配置数据源
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
username: root
password: password
driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
slave_1:
url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
username: root
password: password
driver-class-name: com.mysql.jdbc.Driver
slave_2:
url: ENC(xxxxx) # 内置加密
username: ENC(xxxxx)
password: ENC(xxxxx)
driver-class-name: com.mysql.jdbc.Driver
#......省略
#以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
3. 使用 @DS
切换数据源。
@DS
可以注解在方法上或类上,同时存在就近原则方法上注解
优先于类上注解
。
@Service
@DS("slave_1")
public class BizServiceImpl implements BizService {
......
}
8. 流式查询
- 功能为
Mybatis
原生功能,通过ResultHandler
进行结果集流式查询 - 适用数据跑批或大数据业务处理场景
常用方法:
getResultObject
: 获取数据库每一条记录getResultCount
: 获取下一条结果集都会滚动+1, 等同于下标记录,从1开始stop
: 停止继续处理,等同于break出去
使用示例:
// 结合分页,按批次从数据库拉去数据出来跑批,例如从数据库获取10w记录,做数据处理
Page<User> page = new Page<>(1, 100000);
baseMapper.selectList(page, Wrappers.emptyWrapper(), resultContext -> {
// 依次得到每条业务记录
System.out.println("当前处理第" + resultContext.getResultCount() + "条记录.");
User user = resultContext.getResultObject();
System.out.println(user);
//做自己的业务处理,比如分发任务
});
// 从数据库获取表所有记录,做数据处理
baseMapper.selectList(Wrappers.emptyWrapper(), resultContext -> {
// 依次得到每条业务记录
System.out.println("当前处理第" + resultContext.getResultCount() + "条记录.");
User user = resultContext.getResultObject();
System.out.println(user);
//做自己的业务处理,比如分发任务
});