MyBatisPlus学习记录
MyBatis 和 MyBatisPlus 不能同时存在
1、新建一个SpringBoot项目 在 pom.xml 文件中加入如下代码:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
2、在application.yml文件中加入如下代码:
spring:
datasource:
name: study_db (自己对应的数据库名称)
url: jdbc:mysql://localhost:3306/study_db?useUnicode=true&useSSL=FALSE&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: ****** (自己对应的数据库密码)
driver-class-name: com.mysql.cj.jdbc.Driver
server:
port: 8888
3、建立实体类(要和数据库中类型字段保持一致)
package com.xu.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private Integer age;
private String email;
}
4、新建mapper文件夹,建对应的mapper文件(文件类型是接口文件),在对应的Mapper上面继承基本的接口BaseMapper
package com.xu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xu.pojo.User;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.stereotype.Repository;
//在对应的Mapper上面继承基本的接口BaseMapper
@Repository //代表持久层
public interface UserMapper extends BaseMapper<User> {
//所有的crud操作都已经编写完成了
//你不需要像以前一样配置一大堆文件了
}
5、主启动类上面加上@MapperScan("com.xu.mapper") 里面是对应的mapper文件路径
package com.xu;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//扫描我们的mapper文件夹
@MapperScan("com.xu.mapper")
@SpringBootApplication
public class StudyMybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(StudyMybatisPlusApplication.class, args);
}
}
以上步骤完成之后,就可以测试了
package com.xu;
import com.xu.mapper.UserMapper;
import com.xu.pojo.User;
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 StudyMybatisPlusApplicationTests {
//继承了BaseMapper,所有的方法都来自父类,我们也可以编写自己的扩展方法!
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
//参数是一个Wrapper,条件构造器,这里我们先不用,初始化为null
//查询全部用户
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
答:MyBatisPlus
答:MyBatisPlus 都写好了
只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
启动即会自动注入CURD,性能基本无损耗,直接面向对象操作,BaseMapper
内置通用Mapper、通用Service,仅仅通过少量配置便可实现单表大部分CRUD操作,更有强大的条件构造器,满足各类使用需求,简单的CRUD操作,可以直接用它
通过Lambda表达式,方便的编写各类查询条件,无需担心字段写错
支持多达4种主键策略(内含分布式唯一ID生成器-Sequence),可自由配置,完美解决主键问题
支持ActiveRecord形式调用,实体类只需继承Model类即可进行强大的CRUD操作
支持全局通用方法注入(Write once,use anywhere)
采用代码或者Maven插件可快速生成Mapper、Model、Service、Controller层代码,支持模板引擎,更有超多自定义配置等你来使用(自动帮你生成代码)
基于MyBatis物理分页,开发者无须担心具体操作,配置好插件后,写分页等同于普通List查询
支持MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer等多种婆数据库
可输出sql语句以及其执行时间,建议开发测试启用该功能
提供全表delete、update等操作智能分析阻断,也可以自定义拦截规则,预防误操作
在application.yml文件中加入以下代码:(log-impl后面的值可用得有很多,这里只用了控制台输出)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
运行程序后控制台输出日志如下:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7c447c76] was not registered for synchronization because synchronization is not active
2021-05-12 16:18:33.472 INFO 23164 --- [ main] com.zaxxer.hikari.HikariDataSource : study_db - Starting...
2021-05-12 16:18:33.842 INFO 23164 --- [ main] com.zaxxer.hikari.HikariDataSource : study_db - Start completed.
JDBC Connection [HikariProxyConnection@1512273713 wrapping com.mysql.cj.jdbc.ConnectionImpl@7d2998d8] will not be managed by Spring
==> Preparing: SELECT id,name,age,email FROM user
==> Parameters:
<== Columns: id, name, age, email
<== Row: 1, Jone, 18, test1@baomidou.com
<== Row: 2, Jack, 20, test2@baomidou.com
<== Row: 3, Tom, 28, test3@baomidou.com
<== Row: 4, Sandy, 21, test4@baomidou.com
<== Row: 5, Billie, 24, test5@baomidou.com
<== Total: 5
这个日志输出很方便开发者查询数据库操作信息,很好用!
分布式系统唯一id生成:https://www.cnblogs.com/haoxinyue/p/5208136.html
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心**是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake 雪花算法支持的TPS可以达到419万左右(2^22*1000)。 雪花算法在工程实现上有单机版本和分布式版本。单机版本如下,分布式版本可以参看美团leaf算法:https://github.com/Meituan-Dianping/Leaf 可以保证几乎全球唯一了!
1、实体类字段上 加上注解@TableId(type = IdType.AUTO)(type的值有多种选择)
2、数据库中的对应主键字段一定要是自增的!
3、测试插入数据即可!
AUTO(0), // 数据库id自增
NONE(1), // 未设置主键
INPUT(2), // 手动输入
ASSIGN_ID(3),
ASSIGN_UUID(4),
/** @deprecated */
@Deprecated
ID_WORKER(3), // 默认的全局唯一id
/** @deprecated */
@Deprecated
ID_WORKER_STR(3), // ID_WORKER 字符串表示法
/** @deprecated */
@Deprecated
UUID(4); // 全局唯一id uuid
//测试更新(update)
@Test
public void testUpdate(){
User user = new User();
// 可以通过条件自动拼接动态sql
user.setId((long) 45);
user.setName("e手动");
user.setAge(18);
// 注意:updateById 的参数是一个对象!
int result = userMapper.updateById(user);
System.out.println(result);
}
日志输出如下:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@f951a7f] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@447477005 wrapping com.mysql.cj.jdbc.ConnectionImpl@22a0d4ea] will not be managed by Spring
==> Preparing: UPDATE user SET name=?, age=? WHERE id=?
==> Parameters: e手动(String), 18(Integer), 45(Long)
<== Updates: 1
所有的SQL都是自动帮你动态配置的!使用起来很方便!
创建时间、修改时间!这些操作一般都是自动化完成的,我们不希望手动更新!
阿里巴巴开发手册要求:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需要自动化!
直接在数据库中设置默认值和更新操作
1、添加对应时间字段(不要设置默认值和更新操作) 2、实体类字段属性上添加TableField注解
// 字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
3、编写处理器处理相应注解
package com.xu.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
@Component //一定不要忘记把处理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {
// 插入时的填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始插入填充......");
// setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
// 更新时的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("开始更新填充......");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
4、测试插入、测试更新、观察时间即可!
在面试过程中,我们经常会被问到乐观锁,悲观锁!这个其实很简单
乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论干什么都不去上锁!如果出现了问题,就再次更新值测试!
悲观锁:顾名思义十分悲观,它总是认为会出现问题,无论干什么都去上锁!再去操作!
这里我们主要讲解乐观锁机制!
- 去除记录时,获取当前version
- 更新时,带上这个version
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
乐观锁:1、先查询,获得版本号 version = 1
--A
update user set name = "xu",version = version + 1
where id = 2 and version = 1
--B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败!
update user set name = "xu",version = version + 1
where id = 2 and version = 1
- 给数据库中添加version字段
- 对应实体类加上version字段并加上@Version注解
@Version //乐观锁的Version注解
private Integer version;
- 注册组件
package com.xu.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//扫描我们的mapper文件夹
@MapperScan("com.xu.mapper") // 测试乐观锁移到了这,原先在主启动器上面
@EnableTransactionManagement //开启事务
@Configuration //代表是一个配置类
public class MyBatisPlusConfig {
// 注册乐观锁插件(新版,旧版已弃用)
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
- 测试乐观锁(在测试类中进行测试)
// 测试乐观锁成功
@Test
public void testLockSuccess(){
//1、查询用户信息
User user = userMapper.selectById(45);
//2、修改用户信息
user.setName("小白");
user.setAge(10);
//3、执行更新操作
userMapper.updateById(user);
}
测试结果如下:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@508a65bf] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@401792389 wrapping com.mysql.cj.jdbc.ConnectionImpl@1894e40d] will not be managed by Spring
==> Preparing: SELECT id,name,age,email,version,create_time,update_time FROM user WHERE id=?
==> Parameters: 45(Integer)
<== Columns: id, name, age, email, version, create_time, update_time
<== Row: 45, e手动, 18, 14s.com, 1, null, 2021-05-12 18:36:18
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@508a65bf]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ede46f6] was not registered for synchronization because synchronization is not active
2021-05-13 09:56:58.611 INFO 18852 --- [ main] com.xu.handler.MyMetaObjectHandler : 开始更新填充......
JDBC Connection [HikariProxyConnection@278986288 wrapping com.mysql.cj.jdbc.ConnectionImpl@1894e40d] will not be managed by Spring
==> Preparing: UPDATE user SET name=?, age=?, email=?, version=?, update_time=? WHERE id=? AND version=?
==> Parameters: 小白(String), 10(Integer), 14s.com(String), 2(Integer), 2021-05-13 09:56:58.611(Timestamp), 45(Long), 1(Integer)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ede46f6]
// 测试乐观锁失败,多线程如下
@Test
public void testLockFail(){
// 线程1
User user = userMapper.selectById(45);
user.setName("小白122");
user.setAge(10);
// 模拟另外一个线程执行了插队操作
User user2 = userMapper.selectById(45);
user2.setName("小白22333");
user2.setAge(10);
userMapper.updateById(user2);
// 可以用自旋锁来多次尝试提交
userMapper.updateById(user); // 如果没有乐观锁就会覆盖插队线程的值
}
测试结果如下:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@216e0771] was not registered for synchronization because synchronization is not active
2021-05-13 10:10:36.073 INFO 15436 --- [ main] com.xu.handler.MyMetaObjectHandler : 开始更新填充......
JDBC Connection [HikariProxyConnection@1905280105 wrapping com.mysql.cj.jdbc.ConnectionImpl@5cbe2654] will not be managed by Spring
==> Preparing: UPDATE user SET name=?, age=?, email=?, version=?, update_time=? WHERE id=? AND version=?
==> Parameters: 小白22333(String), 10(Integer), 14s.com(String), 3(Integer), 2021-05-13 10:10:36.073(Timestamp), 45(Long), 2(Integer)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@216e0771]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@fab35b1] was not registered for synchronization because synchronization is not active
2021-05-13 10:10:36.082 INFO 15436 --- [ main] com.xu.handler.MyMetaObjectHandler : 开始更新填充......
JDBC Connection [HikariProxyConnection@1778994610 wrapping com.mysql.cj.jdbc.ConnectionImpl@5cbe2654] will not be managed by Spring
==> Preparing: UPDATE user SET name=?, age=?, email=?, version=?, update_time=? WHERE id=? AND version=?
==> Parameters: 小白122(String), 10(Integer), 14s.com(String), 3(Integer), 2021-05-13 10:10:36.082(Timestamp), 45(Long), 2(Integer)
<== Updates: 0 //注意这里并没有执行更新操作(乐观锁阻止了本次操作)
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@fab35b1]
// 测试按照id查询
@Test
public void testSelectById(){
User user = userMapper.selectById(45);
System.out.println(user);
}
// 测试批量查询
@Test
public void testSelectBatchId(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1,2,3));
System.out.println(users);
}
// 按条件查询之一使用map操作
@Test
public void testSelectBatchIds(){
HashMap<String,Object> map = new HashMap<>();
// 自定义查询
map.put("name","小白22333");
List<User> users = userMapper.selectByMap(map);
System.out.println(users);
}
分页网站使用的十分之多!
- 原始的limit进行分页
- pageHelper第三方插件
- MP其实也内置了分页插件
如何使用?步骤如下:
1、配置分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 注册乐观锁插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); // 注册分页插件
return interceptor;
}
2、直接使用
// 测试分页查询
@Test
public void testPageSelect(){
// current:当前页 size:页面大小
Page<User> page = new Page<>(1,10);
userMapper.selectPage(page,null);
System.out.println(page.getRecords());
}
测试结果如下:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2776015d] was not registered for synchronization because synchronization is not active
2021-05-13 11:06:49.752 INFO 7840 --- [ main] com.zaxxer.hikari.HikariDataSource : study_db - Starting...
2021-05-13 11:06:49.962 INFO 7840 --- [ main] com.zaxxer.hikari.HikariDataSource : study_db - Start completed.
JDBC Connection [HikariProxyConnection@1407986024 wrapping com.mysql.cj.jdbc.ConnectionImpl@58ff8d79] will not be managed by Spring
==> Preparing: SELECT COUNT(*) FROM user
==> Parameters:
<== Columns: COUNT(*)
<== Row: 15
<== Total: 1
==> Preparing: SELECT id,name,age,email,version,create_time,update_time FROM user LIMIT ?
==> Parameters: 10(Long)
<== Columns: id, name, age, email, version, create_time, update_time
<== Row: 1, Jone, 18, test1@baomidou.com, 1, null, null
<== Row: 2, Jack, 20, test2@baomidou.com, 1, null, null
<== Row: 3, Tom, 28, test3@baomidou.com, 1, null, null
<== Row: 4, Sandy, 21, test4@baomidou.com, 1, null, null
<== Row: 5, Billie, 24, test5@baomidou.com, 1, null, null
<== Row: 12, 2, 23, 123@323.com, 1, null, null
<== Row: 23, e, 23, 121@12.com, 1, null, null
<== Row: 42, e, 24, 14s.com, 1, null, null
<== Row: 45, 小白22333, 10, 14s.com, 3, null, 2021-05-13 10:10:36
<== Row: 46, e, 14, 14s.com, 1, null, null
<== Total: 10
// 测试删除
@Test
public void testDelete(){
userMapper.deleteById(2); // 根据 id 删除单个数据
userMapper.deleteBatchIds(Arrays.asList(1,3)); //根据 id 删除多个数据
HashMap<String,Object> map = new HashMap<>();
map.put("name","2");
userMapper.deleteByMap(map); // 按条件删除数据
}
工作中,我们会遇到一些问题,逻辑删除!
物理删除:从数据库中直接移除
逻辑删除:在数据库中没有被移除,而是通过一个变量来让它失效!deleted=0 => deleted=1
管理员可以查看被删除的记录,防止数据的丢失,相当于回收站!
- 在数据库中添加deleted字段 默认值设置为0
- 在实体类中添加deleted字段,并添加@TableLogic注解
@TableLogic // 逻辑删除注解
private Integer deleted;
- 配置(@Bean相关配置高版本后已经不需要了),application.yml中配置如下
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)
- 测试一下删除!
// 测试删除
@Test
public void testDelete(){
userMapper.deleteById(4); //根据id删除单个数据
userMapper.deleteBatchIds(Arrays.asList(1,3)); //根据id删除多个数据
HashMap<String,Object> map = new HashMap<>();
map.put("name","e3");
userMapper.deleteByMap(map); // 按条件删除数据
}
输出日志如下:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b275174] was not registered for synchronization because synchronization is not active
2021-05-13 14:38:14.714 INFO 20120 --- [ main] com.zaxxer.hikari.HikariDataSource : study_db - Starting...
2021-05-13 14:38:14.955 INFO 20120 --- [ main] com.zaxxer.hikari.HikariDataSource : study_db - Start completed.
JDBC Connection [HikariProxyConnection@1825903149 wrapping com.mysql.cj.jdbc.ConnectionImpl@2c7a8af2] will not be managed by Spring
==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
==> Parameters: 4(Integer)
<== Updates: 1 // 逻辑删除本质进行的是更新操作
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b275174]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b2f5fcf] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1687702287 wrapping com.mysql.cj.jdbc.ConnectionImpl@2c7a8af2] will not be managed by Spring
==> Preparing: UPDATE user SET deleted=1 WHERE id IN ( ? , ? ) AND deleted=0
==> Parameters: 1(Integer), 3(Integer)
<== Updates: 0 // 逻辑删除本质进行的是更新操作
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b2f5fcf]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@53ec2968] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@512407823 wrapping com.mysql.cj.jdbc.ConnectionImpl@2c7a8af2] will not be managed by Spring
==> Preparing: UPDATE user SET deleted=1 WHERE name = ? AND deleted=0
==> Parameters: e3(String)
<== Updates: 1 // 逻辑删除本质进行的是更新操作
之后查询被逻辑删除的数据
// 测试查询
@Test
public void testSelectById(){
User user = userMapper.selectById(4);
System.out.println(user);
}
输出日志如下:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@61dde151] was not registered for synchronization because synchronization is not active
2021-05-13 14:44:10.735 INFO 25160 --- [ main] com.zaxxer.hikari.HikariDataSource : study_db - Starting...
2021-05-13 14:44:11.005 INFO 25160 --- [ main] com.zaxxer.hikari.HikariDataSource : study_db - Start completed.
JDBC Connection [HikariProxyConnection@278536229 wrapping com.mysql.cj.jdbc.ConnectionImpl@2241f05b] will not be managed by Spring
==> Preparing: SELECT id,name,age,email,version,deleted,create_time,update_time FROM user WHERE id=? AND deleted=0
==> Parameters: 4(Integer)
<== Total: 0 // 没有查询到结果
十分重要:Wrapper 我们写一些复杂的sql可以用它来替代!
- 测试1
@Test
public void wrapperSelect(){
// 查询name不为空,邮箱不为空,年龄大于等于12的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.isNotNull("email")
.ge("age",12);
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}
- 测试2
@Test
public void wrapperSelectByName(){
// 根据name查询一条用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","小白22333");
User user = userMapper.selectOne(wrapper);
System.out.println(user);
}
- 测试3
@Test
public void wrapperSelectFilter(){
// 查询年龄在10到25之间的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",10,25);
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}
- 测试4
@Test
public void selectBySql(){
// 通过sql语句查询
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("age","select age from user where age < 30");
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}