12.mybatis_plus

1、MyBatis-Plus概述

1.1、简介

官网:http://mp.baomidou.com
参考教程:http://mp.baomidou.com/guide

MyBatis-Plus(简称 MP)是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

1.2、特性

  1. 无侵入:只做增强不做改变,引入它不会对现有工程产生影响
  2. 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  3. 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分CRUD 操作,更有强大的条件构造器,满足各类使用需求
  4. 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  5. 支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库
  6. 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  7. 支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML启动
  8. 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  9. 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  10. 支持关键词自动转义:支持数据库关键词(order、key…)自动转义,还可自定义关键词
  11. 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、Model 、Service 、Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  12. 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  13. 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  14. 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
  15. 内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击

2、快速入门

说明:快速开始参考:http://mp.baomidou.com/guide/quick-start.html
测试项目: mybatis_plus
数据库:mybatis_plus

2.1、数据库创建

  1. 创建数据库:mybatis_plus
  2. 创建User表
    在这里插入图片描述
    对应的 SQL 脚本
DROPTABLE IF EXISTS user;

CREATETABLE user(    
	id BIGINT(20) NOTNULL 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)
);

	DELETEFROM user;
	
	INSERTINTO 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');

2.2、初始化项目

  1. 使用 Spring Initializr 快速初始化一个 Spring Boot 工程
  2. 删除多余的项目杂文件,导入pom依赖
<!--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>

说明:引入MyBatis-Plus之后请不要再次引入MyBatis以及MyBatis-Spring,以避免因版本差异导致的问题

2.3、配置

MySQL 5 和 MySQL 8 的区别需要注意
mysql5

#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456

mysql8以上(spring boot 2.1)

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

说明:这里的 url 使用了 ?serverTimezone=GMT%2B8 后缀,因为Spring Boot 2.1 集成了 8.0版本的jdbc驱动,这个版本的 jdbc 驱动需要添加这个后缀,否则运行测试用例报告如下错误:

java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' isunrecognized or represents more1

这里的 driver-class-name 使用了 com.mysql.cj.jdbc.Driver ,在 jdbc 8 中建议使用这个驱动,之前的 com.mysql.jdbc.Driver 已经被废弃,否则运行测试用例的时候会有 WARN 信息

2.4、代码编写

  1. 编写实体类
package com.coding.mybatis.pojo;
import lombok.Data;
@Data
public class User {
	private Long id;
	private String name;
	private Integer age;
	private String email;
	}
  1. 编写Mapper接口
package com.coding.mybatis.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.coding.mybatis.pojo.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {

}

IDEA在 userMapper 处报错,因为找不到注入的对象,因为类是动态创建的,但是程序可以正确的执行。为了避免报错,可以在 dao 层的接口上添加 @Repository 注解

  1. 主启动类的编写
package com.coding.mybatis;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//在 Spring Boot 启动类中添加 `@MapperScan` 注解,扫描 Mapper 文件夹@MapperScan("com.coding.mybatis.mapper")
@SpringBootApplication
public class MybatisPlusApplication {
	public staticvoid main(String[] args) {
		SpringApplication.run(MybatisPlusApplication.class, args);    
		}
	}

2.5、测试

在test目录中,添加测试类,进行功能测试:

@SpringBootTest
class MybatisPlusApplicationTests {
	@Autowired
	private UserMapper userMapper;
	@Test
	voidcontextLoads() {
		System.out.println(("----- selectAll method test ------"));
		//查询全部的用户		  
		List<User> users = userMapper.selectList(null);
		users.forEach(System.out::println);    
	}
}

说明:UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件,即查询全部的用户
控制台输出结果:

User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

2.6、配置日志

有的时候,为了方便查看具体的SQL,我们会将打开日志功能,properties再次运行,查看SQL输出日志

#mybatis日志 
mybatis-plus.configuration.logimpl = org.apache.ibatis.logging.stdout.StdOutImpl

再次运行,查看SQL输出日志

3、CRUD接口扩展

3.1、CRUD

1、查询Select

  1. 根据id查询记录
@Test
public void testSelectById(){
	User user=userMapper.selectById(1L);
	System.out.println(user);}
//SELECT * FROM user WHERE id=?
  1. 批量查询通过多个id (完成了动态sql的foreach的功能)
@Test
public void testSelectBatchIds(){
	List<User> users= userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
	users.forEach(System.out::println);
}
/*SELECT id,name,age,email,create_time,update_time,version FROM userWHERE id IN ( 1 , 2 , 3 )*/
  1. 简单的条件查询,通过map封装查询条件
@Test
public void testSelectByMap(){
	HashMap<String, Object> map= newHashMap<>();
	map.put("name", "coding");
	map.put("age", 18);
	List<User> users=userMapper.selectByMap(map);
	users.forEach(System.out::println);
	}

注意:map中的key对应数据库中的列名。如:数据库user_id,实体类是userId,这时map的key需要填写user_id

2、Insert插入实现

@Test 
public void testInsert(){    
	User user = new User();    
	user.setName("coding");    
	user.setAge(18);    
	user.setEmail("24736743@qq.com");
    int result = userMapper.insert(user);    
    System.out.println(result); //影响的行数    
    System.out.println(user); //id自动回填 }

注意:数据库插入id值默认为:全局唯一id
在这里插入图片描述
3、更新Update
注意:update时生成的sql自动是就是动态sql !

-- 要求
UPDATE user SET age=? WHERE id=?
//测试类
@Test
public void testUpdateById(){
	Useruser=newUser();
	user.setId(1L);
	user.setAge(28);
	
	//虽然是ID,但是参数时需要一个User
	int result=userMapper.updateById(user);
	System.out.println(result);
}

查看结果:
在这里插入图片描述
4、删除Delete

  1. 根据id删除记录
@Test
public void testDeleteById(){
	int result=userMapper.deleteById(8L);
	System.out.println(result);
}
	//DELETE FROM user WHERE id=?
  1. 批量删除
@Test
public void testDeleteBatchIds() {
	intresult=userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
	System.out.println(result);
}
//DELETE FROM user WHERE id IN ( ? , ? , ? )
  1. 简单的条件查询删除
@Test
public void testDeleteByMap() {
	HashMap<String, Object> map= newHashMap<>();
	map.put("name", "coding");
	map.put("age", 18);
	int result=userMapper.deleteByMap(map);
	System.out.println(result);
}
//DELETE FROM user WHERE name = ? AND age = ?

5.逻辑、物理删除

物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

  1. 数据库中添加 deleted字段
ALTERTABLE `user` ADD COLUMN `deleted` boolean DEFAULT 0
  1. 实体类添加deleted字段,并加上 @TableLogic 注解
//并加上 @TableLogic 注解和 @TableField(fill = FieldFill.INSERT) 注解
@TableLogic//逻辑删除
private Integer deleted;
  1. application.properties 加入配置,此为默认值,如果你的默认值和mybatis-plus默认的一样,该配置可无
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
  1. 在 MybatisPlusConfig 中注册 Bean
//逻辑删除
@Bean
public ISqlInjector sqlInjector() {
	return new LogicSqlInjector();
}
  1. 测试逻辑删除
// 测试逻辑删除
@Test
public void testLogicDelete() {
int result = userMapper.deleteById(1L);
System.out.println(result);}
测试后发现,数据并没有被删除,deleted字段的值由0变成了1
分析打印的sql语句,是一条update
注意:被删除数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作

  1. 测试逻辑删除后的查询,mybatis-plus中查询操作也会自动添加逻辑删除字段的判断
//测试逻辑删除后的查询:不包括被逻辑删除的记录
@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

3.2、主键策略

1、 ID_WORKER

MyBatis-Plus默认的主键策略是:ID_WORKER 全局唯一ID

雪花算法:
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit 作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水 号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

2、自增策略

要想主键自增需要配置如下主键策略:

  1. 需要在创建数据表的时候设置主键自增
    在这里插入图片描述

  2. 实体字段中配置 @TableId(type = IdType.AUTO)

@TableId(type = IdType.AUTO) 
private Long id;

要想影响所有实体的配置,可以设置全局主键配置:

#全局设置主键生成策略 
mybatis-plus.global-config.db-config.id-type=auto

其它主键策略:分析 IdType 源码可知

@Getter 
public enum IdType {
	//数据库ID自增    
    AUTO(0),   
             
    //该类型为未设置主键类型    
  	 NONE(1),
  	 
    //用户输入ID:该类型可以通过自己注册自动填充插件进行填充    
    //用户手动setId;    
    INPUT(2),      
  
    /* 以下3种类型、只有当插入对象ID为空,才自动填充。 */    
    //全局唯一ID (idWorker)    
    ID_WORKER(3),    
        
    //全局唯一ID (UUID)    
    UUID(4),        
    
    //字符串全局唯一ID (idWorker 的字符串表示)    
    ID_WORKER_STR(5);
    
    private int key;
    IdType(int key) {
            this.key = key;    
    } 
}

3.3、自动填充

项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
阿里的规范中说明了,数据库表中必须有三个字段。id,创建时间,更新时间。

我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作!

方案一:数据库级别的自动填充,分别设置默认值
1、在User表中添加datetime类型的新的字段 create_time、update_time
在这里插入图片描述

2、实体类上增加字段

import java.util.Date;
@Data
public class User {
	private Long id;
	private String name;
	private Integer age;
	private String email;
	//时间操作
	private Date createTime;
	private Date updateTime;
}

3、测试insert方法!查看数据库,现在我们并没有对这个两个字段做操作,插入为null
在这里插入图片描述

4、我们在数据库级别设置默认值,当前时间,并让更新时间自动更新 CURRENT_TIMESTAMP
在这里插入图片描述

5、再次测试insert方法,查看结果,插入OK!
在这里插入图片描述

6、对这个用户执行update方法,查看结果,更新成功!
在这里插入图片描述

方案二:业务层处理
1、删除掉数据库的默认值和更新操作!现在使用Mybatis-plus配置!
2、实体类上添加注解


@Data
public class User {   
	 ......
	 @TableField(fill=FieldFill.INSERT)
	 private Date createTime;
	 //@TableField(fill = FieldFill.UPDATE)
	 @TableField(fill=FieldFill.INSERT_UPDATE)
	 private Date updateTime;
}

3、新建一个handler包,实现元对象处理器接口,注意:不要忘记添加 @Component 注解

package com.coding.mybatis.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;importorg.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
@Component    //不要忘记添加@Component 注解
public class MyMetaObjectHandler implements MetaObjectHandler {
	//插入的时候自动填充
	@Override
	public void insertFill(MetaObject metaObject) {
	log.info("start insert fill ....");
	//三个参数:
	//实体类属性名
	//要填充的内容,必须和实体类中字段类型相同
	//metaObject
	this.setFieldValByName("createTime", newDate(), metaObject);
	this.setFieldValByName("updateTime", newDate(), metaObject);
	}
	//更新的时候自动填充
	@Override
	public void updateFill(MetaObjectmetaObject) {
	log.info("start update fill ....");
	this.setFieldValByName("updateTime", newDate(), metaObject);
	}
}

3.4、乐观锁

**主要适用场景:**当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新。

乐观锁理论:

  1. 取出记录时,获取当前version:假设取出的version=1
SELECT id,name,age,email,create_time,update_time,version FROM user WHEREid=1
  1. 更新时,带上这个version
UPDATE USER SET `name`='coding', `version`=`version` + 1WHERE id=1AND`version`=1
  1. 执行更新时, set version = newVersion where version = oldVersion
  2. 如果version不对,就更新失败
  3. 乐观锁SQL
update `user` SET `name`= 'coding',`version` = `version` + 1where id = 2and `version` = 1

-- 如果第一个线程在修改这个值的之后,第二个线程抢先执行完了,那么第一条则执行不成功,因为查询不到!这就是乐观锁的原理

手动代码测试:
1、数据库中添加version字段

LTERTABLE `user` ADD COLUMN `version` INT DEFAULT 1

2、实体类添加version字段并添加 @Version 注解

@Version
private Integer version;
说明:
支持的数据类型只有 int,Integer,long,Long,Date,Timestamp,LocalDateTime
整数类型下new Version = oldVersion + 1  new Version会回写到entity中
仅支持updateById(id)update(entity, wrapper)方法

3、建包config,创建文件MybatisPlusConfig.java此时可以删除主类中的@MapperScan扫描注解

package com.coding.mybatis.config;importorg.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement
@Configuration
@MapperScan("com.coding.mybatis.mapper")
public class MybatisPlusConfig {

}

4、在 MybatisPlusConfig 中注册 Bean

//乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
	return newOptimisticLockerInterceptor();
}

5、测试乐观锁成功Demo,测试后分析打印的sql语句,将version的数值进行了加1操作

//测试乐观锁插件
@Test
public void testOptimisticLocker() {
	//查询
	Useruser=userMapper.selectById(1L);
	//修改数据
	user.setName("coding");
	user.setEmail("24736743@qq.com");
	//执行更新
	userMapper.updateById(user);
}

在这里插入图片描述

6、测试乐观锁失败Demo,测试后分析打印的sql语句

//测试乐观锁插件失败
@Test
public void testOptimisticLockerFail() {
	//查询
	Useruser=userMapper.selectById(1L);
	//修改数据
	user.setName("coding111");
	user.setEmail("24736743@qq.com");
	//模拟另一个线程中间更新了数据
	//查询
	User user2= userMapper.selectById(1L);
	//修改数据
	user2.setName("coding222");
	user2.setEmail("24736743@qq.com");
	userMapper.updateById(user2);
	
	//执行更新,发现修改无效!
	userMapper.updateById(user);
}

在这里插入图片描述

3.5、分页插件

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
1、配置类中添加分页插件

//分页插件
@Bean
public PaginationInterceptorpaginationInterceptor() {
return newPaginationInterceptor();}

2、测试selectPage分页,通过page对象获取相关数据

@Test
public void testSelectPage() {
	Page<User> page= newPage<>(1,5);
	userMapper.selectPage(page, null);
	page.getRecords().forEach(System.out::println);
	System.out.println(page.getCurrent());
	System.out.println(page.getPages());
	System.out.println(page.getSize());
	System.out.println(page.getTotal());
	System.out.println(page.hasNext());
	System.out.println(page.hasPrevious());
}

//SELECT id,name,age,email,create_time,update_time FROM user LIMIT 0,5

3、测试selectMapsPage分页:结果集是Map

@Test
public void testSelectMapsPage() {
	Page<User> page= newPage<>(1, 5);
	IPage<Map<String, Object>> mapIPage = userMapper.selectMapsPage(page,null);
	//注意:此行必须使用 mapIPage 获取记录列表,否则会有数据类型转换错误
	mapIPage.getRecords().forEach(System.out::println);	    
	System.out.println(page.getCurrent());
	System.out.println(page.getPages());
	System.out.println(page.getSize());
	System.out.println(page.getTotal());
	System.out.println(page.hasNext());
	System.out.println(page.hasPrevious());}

4、SQL 执行性能分析插件

4.1、说明

性能分析拦截器,用于输出每条 SQL 语句及其执行时间!
SQL 性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题。

4.2、配置

1、在 MybatisPlusConfig 中配置

/*** SQL 执行性能分析插件* 开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长*/
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
	PerformanceInterce ptorperformanceInterceptor = new PerformanceInterceptor();
	performanceInterceptor.setMaxTime(100);//ms,超过此处设置的ms则sql不执行
	performanceInterceptor.setFormat(true);
	return performanceInterceptor;
	}

参数说明
maxTime: SQL 执行最大时长,超过自动停止运行,有助于发现问题。
format: SQL是否格式化,默认false

2、Spring Boot 中设置dev环境

#环境设置:dev、test、prod
spring.profiles.active=dev

也可以针对各环境新建不同的配置文件

application-dev.properties
application-test.properties
application-prod.properties

4.3、测试

我们将 maxTime: SQL 执行最大时长设置为 1ms

performanceInterceptor.setMaxTime(1);
//测试性能分析插件
@Test
public void testPerformance() {
	User user= new User();
	user.setName("coding");
	user.setEmail("24736743@qq.com");
	user.setAge(18);
	userMapper.insert(user);
}

SQL执行时间
在这里插入图片描述

报错异常:如果执行时间过长,则抛出异常:The SQL execution time is too large

如果想进行复杂条件查询,那么需要使用条件构造器 Wapper,涉及到如下方法

delete
selectOne
selectCount
selectList
selectMaps
selectObjs
update

5、条件构造器

5.1、wapper介绍

在这里插入图片描述

-Wrapper:条件构造抽象类,最顶端父类
--AbstractWrapper:用于查询条件封装,生成 sql 的 where 条件
---QueryWrapper:Entity 对象封装操作类,不适用lambda语法
---UpdateWrapper:Update 条件封装,用于Entity对象更新操作
---AbstractLambdaWrapper:Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。
----LambdaQueryWrapper:看名称也能明白就是用于Lambda语法使用的查询Wrapper
----LambdaUpdateWrapper: Lambda 更新封装Wrapper

创建一个新的测试类

@SpringBootTest
public class QueryWrapperTests {
	@Autowired
	private UserMapper userMapper;
}

5.2、条件构造器测试

注意:以下条件构造器的方法入参中的column均表示数据库字段
1、ge、gt、le、lt、isNull、isNotNull

ge:大于等于        
gt:大于
le:小于等于        
lt:小于
isNull:字段 is null
isNotNull:字段 is not nul

测试:删除名字为null,并且年龄大于等于12岁的,并且email不为空的人

@Test
public void testDelete() {
	QueryWrapper<User> queryWrapper= new QueryWrapper<>();
	queryWrapper        
		.isNull("name") //为空        
		.ge("age", 12) //大于等于        
		.isNotNull("email"); //不为空
	//通过查询构造器,执行删除操作,逻辑删除这里是
	int result=userMapper.delete(queryWrapper);
	System.out.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

2、eq、ne

eq:等于     
ne:不等于

注意:seletOne返回的是一条实体记录,当出现多条时会报错

@Test
public void testSelectOne() {
	QueryWrapper<User> queryWrapper = new QueryWrapper<>();
	queryWrapper.eq("name", "coding"); //equals
	//查看一个记录,并且未被删除的
	Useruser=userMapper.selectOne(queryWrapper);
	System.out.println(user);
}

SQL日志:

SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name = ?

3、between、notBetween

between: between 值1 and 值2
notbetween:not between 值1 and 值2

包含大小边界

@Test
public void testSelectCount() {
	QueryWrapper<User> queryWrapper = new QueryWrapper<>();
	queryWrapper.between("age", 20, 30);
	Integer count = userMapper.selectCount(queryWrapper);
	System.out.println(count);
}

SQL日志:

SELECTCOUNT(1) FROM user WHERE deleted=0 AND age BETWEEN ? AND?

4、allEq

@Test
public void testSelectList() {
	QueryWrapper<User> queryWrapper = new QueryWrapper<>();
	Map<String, Object> map= new HashMap<>();
	map.put("id", 2);
	map.put("name", "Jack");
	map.put("age", 20);
	queryWrapper.allEq(map); //精准查询
	List<User> users= userMapper.selectList(queryWrapper);
	users.forEach(System.out::println);
}

SQL日志:

SELECT id,name,age,email,create_time,update_time,deleted,version
FROM user
WHERE deleted=0 AND name = ? AND id = ? AND age = ?

5、like、notLike、likeLeft、likeRight

like:       LIKE '%值%'
notLike:    Not LIKE '%值%'
likeLeft:   LIKE '%值'
likeRight:  LIKE '值%'

selectMaps返回Map集合列表

@Test
public void testSelectMaps() {
	//姓名当中不包含e, email用t开头
	QueryWrapper<User> queryWrapper = new QueryWrapper<>();
	queryWrapper        
		.notLike("name", "e")        
		.likeRight("email", "t");
	List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
	//返回值是Map列表
	maps.forEach(System.out::println);
}

SQL日志:

SELECT id,name,age,email,create_time,update_time,version,deleted
FROM user
WHERE deleted=0 AND name NOTLIKE'%e%'AND email LIKE't%'

6、in、notIn、inSql、notinSql、exists、notExis


in、notIn:
notIn("age", 1, 2, 3)--->age not in (1,2,3)

inSql、notinSql:可以实现子查询

例: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6): inSql("id", "select id from table where id < 3")--->id in (select id fromtable where id < 3)
@Test\
public void testSelectObjs() {
	QueryWrapper<User> queryWrapper = new QueryWrapper<>();
	
	//queryWrapper.in("id", 1, 2, 3);
	queryWrapper.inSql("id", "select id from user where id < 3");
	
	List<Object> objects= userMapper.selectObjs(queryWrapper);//返回值是Object列表
	objects.forEach(System.out::println);}

SQL日志:

SELECT id,name,age,email,create_time,update_time,version,deleted
FROM user
WHERE deleted=0 AND id IN (select id  from user where id < 3)

7、or、and

注意:这里使用的是 UpdateWrapper不调用or则默认为使用and连

@Test
public void testUpdate1() {
	//修改值
	User user=new User();
	user.setAge(99);
	user.setName("Andy");
	
	//修改条件
	UpdateWrapper<User> userUpdateWrapper =new UpdateWrapper<>();
	userUpdateWrapper        
		.like("name", "h")        
		.or()        
		.between("age", 20, 30);
	intresult=userMapper.update(user, userUpdateWrapper);
	System.out.println(result);
}

SQL日志:

UPDATE user
SET name=?, age=?, update_time=?
WHERE deleted=0 AND name LIKE? OR age BETWEEN? AND?

8、嵌套or、嵌套and
这里使用了lambda表达式,or中的表达式最后翻译成sql时会被加上圆括号

@Test
public void testUpdate2() {
	//修改值
	User user= new User();
	user.setAge(99);
	user.setName("Andy");
	
	//修改条件
	UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
	userUpdateWrapper        
		.like("name", "h")        
		.or(i->i.eq("name", "李白")
		.ne("age", 20));
	int result= userMapper.update(user, userUpdateWrapper);
	System.out.println(result);
}

SQL日志:

UPDATE user 
SET name=?, age=?, update_time=?
WHERE deleted=0 AND name LIKE ? OR ( name = ? AND age <> ? )

9、orderBy、orderByDesc、orderByAsc

@Test
public void testSelectListOrderBy() {
	QueryWrapper<User> queryWrapper = new QueryWrapper<>();
	queryWrapper.orderByDesc("id");
	List<User>users=userMapper.selectList(queryWrapper);
	users.forEach(System.out::println);
}


SQL日志:

SELECT id,name,age,email,create_time,update_time,deleted,version
FROM user 
WHERE deleted=0 ORDER BY id DESC

10、last

直接拼接到 sql 的最后
注意:只能调用一次,多次调用以最后一次为准有sql注入的风险,请谨慎使用

@Test
public void testSelectListLast() {
	QueryWrapper<User> queryWrapper = new QueryWrapper<>();
	queryWrapper.last("limit 1");
	List<User> users= userMapper.selectList(queryWrapper);
	users.forEach(System.out::println);
}

SQL日志:

SELECT id,name,age,email,create_time,update_time,deleted,version
FROM user
WHERE deleted=0 limit 1

11、指定要查询的列

@Test
public void testSelectListColumn() {
	QueryWrapper<User> queryWrapper= new QueryWrapper<>();
	queryWrapper.select("id", "name", "age");
	List<User> users=userMapper.selectList(queryWrapper);
	users.forEach(System.out::println);
}

SQL日志:

SELECT id,name,age 
FROM user 
WHERE deleted = 0

12、set、setSql

最终的sql会合并 user.setAge(),以及 userUpdateWrapper.set() 和 setSql() 中的字段

@Test
public void testUpdateSet() {
	//修改值
	User user = new User();
	user.setAge(99);
	
	//修改条件
	UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
	userUpdateWrapper        
		.like("name", "h")        
		.set("name", "老李头")//除了可以查询还可以使用set设置修改的字段        
		.setSql(" email = '123@qq.com'");//可以有子查询
	int result= userMapper.update(user, userUpdateWrapper);
}

SQL日志:

UPDATE user 
SET age=?, update_time=?, name=?, email = '123@qq.com'
WHERE deleted=0 AND name LIKE ?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值