一、介绍
1、简介
官网:https://mp.baomidou.com/
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率
而生。
2、特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 支持关键词自动转义:支持数据库关键词(order、key……)自动转义,还可自定义关键词
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
- 内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击
二、环境搭建
1、创建数据库
代码语言:javascript复制create database mybatis_plus;
2、创建 User 表
表结构:
代码语言:javascript复制数据库 Schema 脚本
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
代码语言:javascript复制数据库 Data 脚本
DELETE FROM user;
INSERT INTO user (id, name, age, email)
VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
3、创建项目
初始化工程
使用 Spring Initializr 快速初始化一个 Spring Boot 工程
添加依赖
添加
:spring-boot-starter、spring-boot-starter-test、 mybatis-plus-boot-starter、MySQL、lombok
lombok: 在项目中使用Lombok可以减少很多重复代码的书写。
代码语言:javascript复制<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
注意:
- 引入Mybatis-Plus 之后请不要再次引入 Mybatis 以及 Mybatis-Spring,以避免因版本差异导致的问题。
- 使用lombok 在IDEA 中一定要安装插件,新的idea 版本一般默认都安装插件,如果使用的较低版本,需要手动安装一下。
4、配置
application.properties (请按版本来选择)
- mysql5
#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus
spring.datasource.username=root
spring.datasource.password=123456
- mysql8以上(spring boot 2.1) 注意:driver和url的变化
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT+8
spring.datasource.username=root
spring.datasource.password=123456
这里的 url 使用了 ?serverTimezone=GMT+8
后缀,因为Spring Boot 2.1
集成了 8.0版本的jdbc驱动,这个版本的 jdbc 驱动需要添加这个后缀,否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more
这里的 driver-class-name
使用了 com.mysql.cj.jdbc.Driver
,在 jdbc 8 中 建议使用这个驱动,之前的 com.mysql.jdbc.Driver 已经被废弃,否则运行测试用例的时候会有 WARN 信息
三、MP入门-编写代码
1、主类
在 Spring Boot 启动类中添加 @MapperScan
注解,扫描 Mapper 文件夹
注意:扫描的包名根据实际情况修改
代码语言:javascript复制@SpringBootApplication
@MapperScan("com.oy.mp.mapper")
public class MPApplication {
public static void main(String[] args) {
SpringApplication.run(MPApplication.class, args);
}
}
2、实体
创建包 entity 编写实体类 User.java
(此处使用了 Lombok 简化代码)
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
查看编译结果
3、mapper
创建包 mapper 编写Mapper 接口: UserMapper.java
@Component
public interface UserMapper extends BaseMapper<User> {
}
4、测试
添加测试类,进行功能测试:
代码语言:javascript复制@RunWith(SpringRunner.class)
@SpringBootTest
public class MPApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
// UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper
// 所以不填写就是无任何条件
List<User> users = userMapper.selectList(null);
users.forEach(System.err::println);
}
}
5、配置日志
代码语言:javascript复制查看sql输出日志
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
四、MP-对表的CRUD操作
1、insert
代码语言:javascript复制@RunWith(SpringRunner.class)
@SpringBootTest
public class CRUDTests {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert(){
User user = new User();
user.setName("Helen");
user.setAge(18);
user.setEmail("55317332@qq.com");
int result = userMapper.insert(user);
System.out.println(result); //影响的行数
System.out.println(user); //id自动回填
}
}
注意:
数据库插入 id 值默认认为: 全局唯一的 id
2、主键策略
- ID_WORKER MyBatis-Plus默认的主键策略是:ID_WORKER 全局唯一ID
代码语言:javascript复制工具类
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
/**
* <p>名称:IdWorker.java</p>
* <p>描述:分布式自增长ID</p>
* <pre>
* Twitter的 Snowflake JAVA实现方案
* </pre>
* 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
* 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
* 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
* 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
* 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
* 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
* <p>
* 64位ID (42(毫秒) 5(机器ID) 5(业务编码) 12(重复累加))
*
* @author Polim
*/
public class IdWorker {
// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
private final static long twepoch = 1288834974657L;
// 机器标识位数
private final static long workerIdBits = 5L;
// 数据中心标识位数
private final static long datacenterIdBits = 5L;
// 机器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private final static long sequenceBits = 12L;
// 机器ID偏左移12位
private final static long workerIdShift = sequenceBits;
// 数据中心ID左移17位
private final static long datacenterIdShift = sequenceBits workerIdBits;
// 时间毫秒左移22位
private final static long timestampLeftShift = sequenceBits workerIdBits datacenterIdBits;
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/* 上次生产id时间戳 */
private static long lastTimestamp = -1L;
// 0,并发控制
private long sequence = 0L;
private final long workerId;
// 数据标识id部分
private final long datacenterId;
public IdWorker(){
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
* @param workerId
* 工作机器ID
* @param datacenterId
* 序列号
*/
public IdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 获取下一个ID
*
* @return
*/
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
// 当前毫秒内,则 1
sequence = (sequence 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
long nextId = ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;
return nextId;
}
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
/**
* <p>
* 获取 maxWorkerId
* </p>
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuffer mpid = new StringBuffer();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
/*
* GET jvmPid
*/
mpid.append(name.split("@")[0]);
}
/*
* MAC PID 的 hashcode 获取16个低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId 1);
}
/**
* <p>
* 数据标识id部分
* </p>
*/
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId 1);
}
} catch (Exception e) {
System.out.println(" getDatacenterId: " e.getMessage());
}
return id;
}
}
代码语言:javascript复制User 配置注解
@Data
public class User {
// mp 默认id的生成策略是Long类型的 idWorker, 全局唯一的
@TableId(type = IdType.ID_WORKER)
private Long id;
private String name;
private Integer age;
private String email;
}
- 自增策略
要想主键自增需要配置如下主键策略
- 需要在创建数据表的时候设置主键自增
- 实体字段中配置 @TableId(type = IdType.AUTO)
3、update
3.1 根据Id更新操作
注意:update时生成的sql自动是动态sql:UPDATE user SET age=? WHERE id=?
代码语言:javascript复制@Test
public void testUpdateById(){
User user = new User();
user.setId(1L);
user.setAge(28);
int result = userMapper.updateById(user);
System.err.println(result);
}
3.2 自动填充
项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作:
- 数据库表中添加自动填充字段
在User表中添加datetime类型的新的字段 create_time
、update_time
2. 实体上添加注解
代码语言:javascript复制@Component
public class DataMetaObjctHandler implements MetaObjectHandler {
// 在执行insert语句的时候被拦截操作的
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
// 修改语句
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
3. 测试
3.3 乐观锁
主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
乐观锁实现方式:
- 取出记录时,获取当前当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对, 就更新失败
- 数据库添加 version 字段
2. 实体类添加 version 字段 并添加 @Version 注解
代码语言:javascript复制// 在User类中 乐观锁修改版本号
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
3. 元对象处理接口添加 version 的 insert 默认值
代码语言:javascript复制@Override
public void insertFill(MetaObject metaObject) {
......
this.setFieldValByName("version", 1, metaObject);
}
特别说明:
- 支持的数据类型只有 int、Integer、long、Long、Date、Timestamp、LocalDataTime
- 整型类型下 newVersion = oldVersion 1
- newVersion 会回到 entity 中
- 仅支持 updateById(id) 与 update(entity,wrapper) 方法
- 在 update(entity, wrapper) 方法下,wrapper 不能复用
- 在 MybatisPlusConfig 中注册 Bean
创建配置类
@Configuration
@EnableTransactionManagement
@MapperScan("com.oy.mp.mapper")
public class MPConfig {
/***
* 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
- 测试乐观锁可以修改成功
/**
* 测试 乐观锁插件
*/
@Test
public void testOptimisticLocker(){
// 查询
User user = userMapper.selectById(1L);
// 修改数据
user.setName("Helen Yao");
user.setEmail("helen@qq.com");
user.setAge(21);
// 执行更新
int result = userMapper.updateById(user);
System.err.println(result);
}
4、select
4.1 根据id查询记录
代码语言:javascript复制@Test
public void testSelectById(){
User user = userMapper.selectById(1L);
System.err.println(user);
}
4.2 通过多个id批量查询
动态sql的foreach的功能
代码语言:javascript复制@Test
public void testSelectBatchIds() {
List list = new ArrayList();
list.add(1L);
list.add(2L);
list.add(3L);
List users = userMapper.selectBatchIds(list);
users.forEach(System.err::println);
}
4.3 简单的条件查询
通过map 封装查询条件
代码语言:javascript复制@Test
public void testSelectByMap(){
Map<String, Object> map = new HashMap<>();
map.put("name","Helen");
map.put("age",18);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.err::println);
}
注意:
map 中的key 对应的是数据库中的列名。例如数据库 user_id, 实体类是userId, 这时 map 的 key 需要填写 user_id。
4.4 分页
Mybatis Plus 自带分页插件,只要简单的配置即可实现分页功能
代码语言:javascript复制创建配置类 此时是可以删除主类中的 @MapperScan 扫描注解
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
测试 selectPage 分页
测试:最终通过 page 对象获取相关数据
代码语言:javascript复制@Test
public void testSelectPage(){
Page<User> page = new Page<>(1,5);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.err::println);
System.err.println("当前页:" page.getCurrent());
System.err.println("总页数:" page.getPages());
System.err.println("每页显示记录数:" page.getSize());
System.err.println("总记录数:" page.getTotal());
System.err.println("是否有下一页:" page.hasNext());
System.err.println("是否有上一页:" page.hasPrevious());
}
代码语言:javascript复制测试 selectMapsPage 分页: 结果集是 Map
@Test
public void testSelectMapsPage(){
Page<User> page = new Page<>(1,5);
IPage<Map<String, Object>> Imap = userMapper.selectMapsPage(page, null);
// 注意,此行必须使用 Imap 获或记录列表,否则会与数据类型的转换错误
Imap.getRecords().forEach(System.err::println);
System.err.println(page.getCurrent());
System.err.println(page.getSize());
System.err.println(page.getTotal());
System.err.println(page.hasNext());
System.err.println(page.hasPrevious());
}
5、delete
5.1 根据 id 删除记录
代码语言:javascript复制@Test
public void testDeleteById(){
int result = userMapper.deleteById(1364225405027991553L);
System.err.println(result);
}
5.2 批量删除
代码语言:javascript复制@Test
public void testDeleteBatchIds(){
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(2L);
list.add(3L);
int result = userMapper.deleteBatchIds(list);
System.err.println(result);
}
5.3 简单的条件查询删除
代码语言:javascript复制 @Test
public void testDeleteByMap(){
Map<String, Object> map = new HashMap<>();
map.put("name","Helen");
map.put("age",18);
int result = userMapper.deleteByMap(map);
System.err.println(result);
}
5.4 逻辑删除
- 物理删除: 真实删除, 将对应色数据库中删除,之后查询不到此条被删除数据
- 逻辑删除: 假删除,将对应的数据中是否被删除字段状态修改为”被删除状态”,之后在数据库中仍旧能看到条数据记录
在数据库中添加delete 字段
实体类添加deleted 字段
并加上 @TableLogic 注解 和 @TableField(fill = FieldFill.INSERT) 注解
代码语言:javascript复制@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
代码语言:javascript复制元对象处理器接口添加deleted的insert默认值
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("deleted",0,metaObject);
}
application.properties 加入配置
此为默认值,如果你的默认值和mp默认的一样,该配置可无
代码语言:javascript复制mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
代码语言:javascript复制在 MybatisPlusConfig 中注册 Bean
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
测试逻辑删除
- 测试后发现,数据并没有被删除,deleted 字段的值 0 变成 1
- 测试后分析打印的 sql 语句,是一条 update
注意:
被删除数据的deleted 字段的值必须是0, 才能被选取出来执行逻辑删除的操作
/**
* 测试 逻辑删除
*/
@Test
public void testLogicDelete(){
int result = userMapper.deleteById(1L);
System.err.println(result);
}
测试逻辑删除后的查询
MyBatis Plus中查询操作也会自动添加逻辑删除字段的判断
代码语言:javascript复制/**
* 测试 逻辑删除后的查询:
* 不包括被逻辑删除的记录
*/
@Test
public void testLogicDeleteSelect() {
User user = new User();
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
测试后分析打印的sql语句,包含 WHERE deleted=0
SELECT id,name,age,email,create_time,update_time,deleted FROM user WHERE deleted=0
6、性能分析
性能分析拦截器,用于输出每条 SQL 语句及其执行时间
SQL 性能执行分析,开发环境使用,超出指定时间,停止运行。有助于发现问题
6.1 配置插件
参数说明
- 参数: maxTime: SQL 执行最长时长,超出自动停止运行,有助于发现问题。
- 参数: format: SQL是否格式化,默认 false。
代码语言:javascript复制在 MybatisPlusConfig 中配置
@Bean
@Profile({"dev","test"}) // 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
// performanceInterceptor.setMaxTime() ms, 超出此设置的ms则sql不执行
performanceInterceptor.setMaxTime(100);
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
代码语言:javascript复制Spring Boot 中设置dev环境
#环境设置: dev、test、prod
spring.profiles.active=dev
可以针对各环境新建不同的配置文件 application-dev.properties
、application-test.properties
、application-prod.properties
也可以自定义环境名称: 如test1、test2
6.2 测试
代码语言:javascript复制常规测试
/**
* 测试 性能分析插件
*/
@Test
public void testPerformance(){
User user = new User();
user.setName("Jarry");
user.setEmail("Jarry@gmail.com");
user.setAge(23);
userMapper.insert(user);
}
将maxTime 改小之后再次进行测试
performanceInterceptor.setMaxTime(5);//ms,超过此处设置的ms不执行
如果执行时间过长,则抛出异常:The SQL execution time is too large,
五、条件构造器
如果想进行复杂条件查询,那么需要使用条件构造器 Wapper,涉及到如下方法
- delete
- selectOne
- selectCount
- selectList
- selectMaps
- selectObjs
- update
1、wrapper介绍
- Wrapper : 条件构造抽象类,最顶端父类
- AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
- QueryWrapper : Entity 对象封装操作类,不是用lambda语法
- UpdateWrapper : Update 条件封装,用于Entity对象更新操作
- AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。
- LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper
- LambdaUpdateWrapper : Lambda 更新封装Wrapper
- AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
查询方式 | 说明 |
---|---|
setSqlSelect | 设置 SELECT 查询字段 |
where | WHERE 语句,拼接 WHERE 条件 |
and | AND 语句,拼接 AND 字段=值 |
andNew | AND 语句,拼接 AND (字段=值) |
or | OR 语句,拼接 OR 字段=值 |
orNew | OR 语句,拼接 OR (字段=值) |
eq | 等于= |
allEq | 基于 map 内容等于= |
ne | 不等于<> |
gt | 大于> |
ge | 大于等于>= |
lt | 小于< |
le | 小于等于<= |
like | 模糊查询 LIKE |
notLike | 模糊查询 NOT LIKE |
in | IN 查询 |
notIn | NOT IN 查询 |
isNull | NULL 值查询 |
isNotNull | IS NOT NULL |
groupBy | 分组 GROUP BY |
having | HAVING 关键词 |
orderBy | 排序 ORDER BY |
orderAsc | ASC 排序 ORDER BY |
orderDesc | DESC 排序 ORDER BY |
exists | EXISTS 条件语句 |
notExists | NOT EXISTS 条件语句 |
between | BETWEEN 条件语句 |
notBetween | NOT BETWEEN 条件语句 |
addFilter | 自由拼接 SQL |
last | 拼接在最后,例如:last(“LIMIT 1”) |
2、示例
代码语言:javascript复制ge、gt、le、lt、isNull、isNotNull
@Test
public void testDelete(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("name")
.ge("age",12)
.isNotNull("email");
int result = userMapper.delete(queryWrapper);
System.err.println("delete return count=" result);
}
测试结果:
SQL:UPDATE user SET deleted=1 WHERE deleted=0 AND name IS NULL AND age >= ? AND email IS NOT NULL
代码语言:javascript复制eq、ne
@Test
public void testSelectOne(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name","Jarry");
User user = userMapper.selectOne(queryWrapper);
System.err.println(user);
}
注意:
selectOne 返回的是一条实体记录,当出现多条时会报错
测试结果:
SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name = ?