一、项目创建
可以选择SpringIntializr创建也可以使用Maven方式创建
选好之后点击下一步
这里只需要选中最基本的依赖项,后续依赖我们会在pom.xml中引入
二、引入依赖
spring Initializr创建项目需要在pom.xml文件的标签中添加如下依赖
<!-- mysql数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
如果是Maven方式创建项目,若想使用SpringBoot还需添加SpringBoot相关依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>MybatisPlus-Demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>MybatisPlus-Demo</name>
<description>MybatisPlus-Demo</description>
<properties>
<java.version>1.8</java.version>
</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>
<scope>test</scope>
</dependency>
<!-- mysql数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
三、创建数据库及引入数据库
1. 创建数据库
若已经有数据库则跳过至步骤二
我这里使用的是Navicat创建数据库
完成数据库创建后添加数据表
-- 判断要创建的表名称是否已经存在
DROP TABLE IF EXISTS student;
CREATE TABLE student(
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 '邮箱',
-- 设置id主键
PRIMARY KEY (id),
-- 在id字段创建普通索引
index(id)
);
-- 插入数据
INSERT INTO student (id, name, age, email)
VALUES
(1001, 'Jone', 18, 'test1@baomidou.com'),
(1002, 'Jack', 20, 'test2@baomidou.com'),
(1003, 'Tom', 28, 'test3@baomidou.com'),
(1004, 'Sandy', 21, 'test4@baomidou.com'),
(1005, 'Billie', 24, 'test5@baomidou.com');
创建表时详细索引参考->文档地址
2. 引入数据库
2.1 连接数据库
数据库连接语句在resource资源目录下的application.properties文件中书写
在MySQL8.0版本后,连接语句发生了变化(相关文档)。
MySQL8.0版本后的语句书写
# 数据库连接配置
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisPlus_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 配置日志 sql语句在执行时不可见,所以为了便于错误排查,需要通过日志打印语句。
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
注意:如果你是5.*数据库版本,就需要将com.mysql.cj.jdbc.Driver改为:com.mysql.jdbc.Driver。
yml文件书写语句
server:
port: 8080
spring:
application:
name: mybatis-plus
datasource:
url: jdbc:mysql://www.xlz.com/mybatis-plus? useEncoding=utf8mb4&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
四、自动创建对应实体类及接口和xml文件
1 在idea中引入数据源
进入数据源后填写相关信息,点击下方测试链接通过后,点击确定按钮
2 使用Mybatis-generator自动创建
在导入完数据源后,找到要映射的数据表。右键选择mybatis-generator选项
进入mybatis-generate tool,填写对应信息
点击ok后,在指定路径总计生成三个文件(文件因路径不同,生成位置不同)。至此自动配置完成。
\
也可以使用语句生成
五、接口测试
一般创建SpringBoot项目中有内置Junit5的,这时可以通过使用快捷键alt+Insert快捷生成测试
书写如下代码,测试是否有数据输出。
@SpringBootTest
class StudentMapperTest{
@Autowired
StudentMapper studentMapper;
@Test
void selectByPrimaryKey (){
Student student = studentMapper.selectByPrimaryKey (1001L);
System.out.println (student);
}
}
六、日志打印
日志主要体现在当运行程序的时候,将会在控制台将会打印日志信息
使用在 application.xml 文件中加入
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
\
七、MybatisPlus常用注解
7.1 @MapperScan
作用: 为了集成Spring而写的注解,该注解主要是扫描某个包目录下的Mapper,将Mapper接口类交给Spring进行管理。
使用位置: 在Springboot启动类上添加
示例:
@SpringBootApplication
@MapperScan("com.example.mybatisplusdemo")
public class MybatisPlusDemoApplication{
public static void main (String[] args){
SpringApplication.run (MybatisPlusDemoApplication.class , args);
}
}
7.2 @Mapper
作用: 在接口类上添加了@Mapper,在运行时会生成相应的接口实现类,这个要一个一个去加,不如用@MapperScan全部扫描添加
添加位置: 接口类上面
示例:
@Mapper
public interface StudentMapper extends BaseMapper<Student>{
...
}
7.3 @TableName
作用: 用于标识实体类对应的表名
添加位置: 实体类之上
示例:
@TableName("user")
public class User {
...
}
7.4 @Data
作用: 简化开发,使用这个注解,就可以省略getter()、setter()、toString()、重写该类的equals()和hashCode()方法
使用位置: 实体类之上
示例:
@Data
public class User {
...
}
7.5 @TableId
作用:
用于标识主键列,MyBatis-Plus在实现增删改查时,会默认将id作为主键列,在插入数据时,若对应字段为空,则默认使用基于雪花算法的策略生成id。
当使用@TableId(value = “id”)语句时,若实体类和表中表示主键的不是id,而是其他字段,例如代码中的uid,MyBatis-Plus会自动识别uid为主键列,否则就会报错。
当使用@TableId(value = “id”,type = IdType.AUTO)语句时,代表着使用数据库的自增策略,注意,该类型请确保数据库设置了id自增,否则无效!
@TableId的功能,也可以写在application.yml配置文件中,配置如下:
mybatis-plus:
global-config:
banner: false
db-config:
# 配置MyBatis-Plus操作表的默认前缀
table-prefix: "t_"
# 配置MyBatis-Plus的主键策略
id-type: auto
# 配置MyBatis日志
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
使用位置: 主键映射字段之上
示例:
/**
* student
* @author
*/
@Data
@TableName("mybatisplus_demo")
public class Student implements Serializable {
/**
* 主键ID,学号
*/
@TableId(value = "id",type = IdType.AUTO )
private Long id;
}
7.6 @TableField
作用: 用于保证实体类中的属性名与数据表中字段名一致。
注: 若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格。
例如实体类属性userName,表中字段user_name,此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格
若实体类中的属性和表中的字段不满足上述条件,例如实体类属性name,表中字段username,此时需要在实体类属性上使用@TableField(“username”)设置属性所对应的字段名
使用位置: 实体类除主键字段外其他映射字段之上
@Data
@TableName("mybatisplus_demo")
public class Student implements Serializable {
/**
* 主键ID,学号
*/
@TableId(value = "id",type = IdType.AUTO )
private Long id;
/**
* 姓名
*/
@TableField(value = "name")
private String name;
}
7.7 @TableLogic
作用: 逻辑删除,并不会永久删除数据,实体类加上这个注解再执行删除方法的时候会变成修改。前台再根据所加注解字段进行显隐即可达到逻辑删除效果。
@Data
@TableName("mybatisplus_demo")
public class Student implements Serializable {
/**
* 主键ID,学号
*/
@TableId(value = "id",type = IdType.AUTO )
private Long id;
/*
删除标识
@TableLogic(value=“原值”,delval=“修改值”)
注解参数
value = “” 未删除的值,默认值为0
delval = “” 删除后的值,默认值为1
*/
@TableField(value = "del")
@TableLogic(value = "0",delval = "1")
private Integer del;
}
\
调用BaseMapper的deleteById(id)或者调用IService的removeById(id)
效果:
没有@TableLogic注解调用deleteById/removeById,直接删除数据。
SQL:delete from table where id = 1
有注解走Update方法
SQL:Update table set isDelete = 1 where id = 1
\
7.8 @Param
作用:用于标识传入参数的名称
使用位置:形参列表
示例:
@Mapper
public interface StudentMapper extends BaseMapper<Student>{
int insert(@Param (value = "record") Student record);
}
与之对应的XML文件就可以使用${record}变量
7.9 @Version
作用: 可以在实体 bean 中使用@Version 注解,通过这种方式可添加对乐观锁定的支持,一个类中只能有一个@Version注解。
不可选属性 | String | ||
---|---|---|---|
可选属性 | int | Integer | Long |
@Data
@TableName("mybatisplus_demo")
public class Student implements Serializable {
/**
* 主键ID,学号
*/
@TableId(value = "id",type = IdType.AUTO )
private Long id;
/**
* 版本号
*/
@Version (value = "version")
private int version;
}
7.10 @EnumValue 和 JsonValue
@JsonValue
可以用在get方法或者属性字段上,一个类只能用一个,当加上@JsonValue注解时,该类的json化结果,只有这个get方法的返回值,而不是这个类的属性键值对.
案例: 男,女,后台存储的是1,2,前端展示的是男女
第一步:
创建枚举类,在需要存储数据库的属性上添加 @EnumValue注解,在需要前端展示的属性上添加 @JsonValue注解;
package com.demo.mybatisplus.constant;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
public enum SexEnum {
MAN(1, "男"),
WOMAN(2, "女");
@EnumValue
private Integer key;
@JsonValue
private String display;
SexEnum(Integer key, String display) {
this.key = key;
this.display = display;
}
public Integer getKey() {
return key;
}
public String getDisplay() {
return display;
}
}
第二步:
application.properties文件里添加配置,定义扫描枚举类的包路径;
#配置枚举 支持通配符 * 或者 ; 分割
mybatis-plus.type-enums-package=com.demo.mybatisplus.constant
#mybatis-plus.configuration.default-enum-type-handler=org.apache.ibatis.type.EnumOrdinalTypeHandler
application.yml则配置
#配置枚举 支持通配符 * 或者 ; 分割
mybatis-plus:
type-enums-package: com.demo.mybatisplus.constant
configuration:
default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
第三步:
pojo中的sex属性设置为枚举SexEnum;
@ApiModelProperty(value = "性别")
@TableField("sex")
private SexEnum sex;
测试:
@Test
public void insert() {
UserInfo userInfo = new UserInfo();
userInfo.setAge(22);
userInfo.setName("李四");
userInfo.setSex(SexEnum.WOMAN);
userInfoMapper.insert(userInfo);
System.out.println(userInfo);
}
注意事项:
- @EnumValue标记的枚举类属性的类型要和数据库字段的类型对应,否则在查询数据的时候无法转化为枚举类型,并显示为null;
- 如果查询的时候,数据库字段的值匹配不到枚举,程序运行时并不会报错,而是显示为null;
- 在保存的时候,前端需要传递@JsonValue标记的枚举类属性的值,即”男/女”;因为Enum的属性ordinal(int),在测试过程中,传枚举值在枚举类中的定义顺序(或者称为索引,顺序从0开始),也可以转换为相应的枚举值,比如:上面定义的SexEnum枚举,前端传0或者”0″,会转换成MAN,传1或者”1″会转换成WOMAN;传其他值会报异常:com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type com.demo.mybatisplus.constant.SexEnum from String “3”: not one of the values accepted for Enum class: [女, 男]或com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type com.demo.mybatisplus.constant.SexEnum from number 3: index value outside legal index range [0..2];
八、MybatisPlus常用方法
8.1 条件构造器 Wrapper
\
介绍 :
- 上图绿色框为抽象类abstract
- 蓝色框为正常class类,可new对象
- 黄色箭头指向为父子类关系,箭头指向为父类
wapper介绍 :
- Wrapper : 条件构造抽象类,最顶端父类,抽象类中提供4个方法西面贴源码展示
- AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
- AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。
- LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper
- LambdaUpdateWrapper : Lambda 更新封装Wrapper
- QueryWrapper : Entity 对象封装操作类,不是用lambda语法
- UpdateWrapper : Update 条件封装,用于Entity对象更新操作
\
常用条件
比较大小: (=,<>,>,>=,<,<=)
eq(R column, Object val); // 等价于 =,例: eq("name", "老王") ---> name = '老王'
ne(R column, Object val); // 等价于 <>,例: ne("name", "老王") ---> name <> '老王'
gt(R column, Object val); // 等价于 >,例: gt("name", "老王") ---> name > '老王'
ge(R column, Object val); // 等价于 >=,例: ge("name", "老王") ---> name >= '老王'
lt(R column, Object val); // 等价于 <,例: lt("name", "老王") ---> name < '老王'
le(R column, Object val); // 等价于 <=,例: le("name", "老王") ---> name <= '老王'
范围:(between、not between、in、not in)
between(R column, Object val1, Object val2); // 等价于 between a and b, 例: between("age", 18, 30) ---> age between 18 and 30
notBetween(R column, Object val1, Object val2); // 等价于 not between a and b, 例: notBetween("age", 18, 30) ---> age not between 18 and 30
in(R column, Object... values); // 等价于 字段 IN (v0, v1, ...),例: in("age",{1,2,3}) ---> age in (1,2,3)
notIn(R column, Object... values); // 等价于 字段 NOT IN (v0, v1, ...), 例: notIn("age",{1,2,3}) ---> age not in (1,2,3)
inSql(R column, Object... values); // 等价于 字段 IN (sql 语句), 例: inSql("id", "select id from table where id < 3") ---> id in (select id from table where id < 3)
notInSql(R column, Object... values); // 等价于 字段 NOT IN (sql 语句)
模糊匹配:(like)
// 等价于 LIKE '%值%',例: like("name", "王") ---> name like '%王%'
like(R column, Object val);
// 等价于 NOT LIKE '%值%',例: notLike("name", "王") ---> name not like '%王%'
notLike(R column, Object val);
// 等价于 LIKE '%值',例: likeLeft("name", "王") ---> name like '%王'
likeLeft(R column, Object val);
// 等价于 LIKE '值%',例: likeRight("name", "王") ---> name like '王%'
likeRight(R column, Object val);
空值比较:(isNull、isNotNull)
isNull(R column); // 等价于 IS NULL,例: isNull("name") ---> name is null
isNotNull(R column); // 等价于 IS NOT NULL,例: isNotNull("name") ---> name is not null
分组、排序:(group、having、order)
groupBy(R... columns); // 等价于 GROUP BY 字段, ..., 例: groupBy("id", "name") ---> group by id,name
orderByAsc(R... columns); // 等价于 ORDER BY 字段, ... ASC, 例: orderByAsc("id", "name") ---> order by id ASC,name ASC
orderByDesc(R... columns); // 等价于 ORDER BY 字段, ... DESC, 例: orderByDesc("id", "name") ---> order by id DESC,name DESC
having(String sqlHaving, Object... params); // 等价于 HAVING ( sql语句 ), 例: having("sum(age) > {0}", 11) ---> having sum(age) > 11
拼接、嵌套 sql:(or、and、nested、apply)
or(); // 等价于 a or b, 例:eq("id",1).or().eq("name","老王") ---> id = 1 or name = '老王'
or(Consumer<Param> consumer); // 等价于 or(a or/and b),or 嵌套。例: or(i -> i.eq("name", "李白").ne("status", "活着")) ---> or (name = '李白' and status <> '活着')
and(Consumer<Param> consumer); // 等价于 and(a or/and b),and 嵌套。例: and(i -> i.eq("name", "李白").ne("status", "活着")) ---> and (name = '李白' and status <> '活着')
nested(Consumer<Param> consumer); // 等价于 (a or/and b),普通嵌套。例: nested(i -> i.eq("name", "李白").ne("status", "活着")) ---> (name = '李白' and status <> '活着')
apply(String applySql, Object... params); // 拼接sql(若不使用 params 参数,可能存在 sql 注入),例: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08") ---> date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
last(String lastSql); // 无视优化规则直接拼接到 sql 的最后,可能存若在 sql 注入。
exists(String existsSql); // 拼接 exists 语句。例: exists("select id from table where age = 1") ---> exists (select id from table where age = 1)
QueryWrapper 条件:
select(String... sqlSelect); // 用于定义需要返回的字段。例: select("id", "name", "age") ---> select id, name, age
select(Predicate<TableFieldInfo> predicate); // Lambda 表达式,过滤需要的字段。
lambda(); // 返回一个 LambdaQueryWrapper
UpdateWrapper 条件:
set(String column, Object val); // 用于设置 set 字段值。例: set("name", null) ---> set name = null
etSql(String sql); // 用于设置 set 字段值。例: setSql("name = '老李头'") ---> set name = '老李头'
lambda(); // 返回一个 LambdaUpdateWrapper```
8.2 Page<>类
属性源码
public class Page<T> implements IPage<T> {
private static final long serialVersionUID = 8545996863226528798L;
// 用来存放查询出来的数据
protected List<T> records;
// 返回记录的总数
protected long total;
// 每页显示条数,默认 10
protected long size;
// 当前页,默认1
protected long current;
// 排序字段信息
protected List<OrderItem> orders;
// 自动优化 COUNT SQL,默认true
protected boolean optimizeCountSql;
// 是否进行 count 查询,默认true
protected boolean isSearchCount;
// 是否命中count缓存,默认false
protected boolean hitCount;
protected String countId;
protected Long maxLimit;
}
\
8.3 mapper层(接口定义层)可以用BaseMapper<>
例如
内部方法总览
方法详细介绍
汇总
【添加数据:(增)】
int insert(T entity); // 插入一条记录
注:
T 表示任意实体类型
entity 表示实体对象
【删除数据:(删)】
int deleteById(Serializable id); // 根据主键 ID 删除
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); // 根据 map 定义字段的条件删除
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper); // 根据实体类定义的 条件删除对象
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); // 进行批量删除
注:
id 表示 主键 ID
columnMap 表示表字段的 map 对象
wrapper 表示实体对象封装操作类,可以为 null。
idList 表示 主键 ID 集合(列表、数组),不能为 null 或 empty
【修改数据:(改)】
int updateById(@Param(Constants.ENTITY) T entity); // 根据 ID 修改实体对象。
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper); // 根据 updateWrapper 条件修改实体对象
注:
update 中的 entity 为 set 条件,可以为 null。
updateWrapper 表示实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
【查询数据:(查)】
T selectById(Serializable id); // 根据 主键 ID 查询数据
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); // 进行批量查询
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); // 根据表字段条件查询
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据实体类封装对象 查询一条记录
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询记录的总条数
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 entity 集合)
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 map 集合)
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(但只保存第一个字段的值)
<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 entity 集合),分页
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 map 集合),分页
注:
queryWrapper 表示实体对象封装操作类(可以为 null)
page 表示分页查询条件
增
插入一条记录
int insert(T entity);
@Test
public void Insert_T(){
Student student=new Student ();
student.setAge (18);
student.setEmail ("165@163.com");
student.setName ("柳宗元");
int insert = studentMapper.insert (student);
System.out.println (insert==0?"插入失败":"插入成功");
}
删
根据主键id删除
int deleteById(Serializable id);
根据 map 定义字段的条件删除
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
@Test
public void deleteByMap_T(){
// 通用删除操作 deleteByMap map要写列名条件 不能是实体属性名
Map<String, Object> map=new HashMap<> ();
// 删除name列中,内容为Jone的记录
map.put ("name","Jone");
int count = studentMapper.deleteByMap (map);
System.out.println (count==0?"删除失败":"删除成功");
}
根据实体类定义的条件删除对象
// 根据实体类定义的 条件删除对象
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
进行批量删除
// 进行批量删除
// idList 表示主键 ID 集合(列表、数组),不能为 null 或 empty
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
@Test
public void deleteBatchIds_T(){
int count = studentMapper.deleteBatchIds (Stream.of (1012,1013).collect(Collectors.toList ()));
System.out.println (count==0?"删除失败":"删除成功");
}
改
根据 ID 修改实体对象。
int updateById(@Param(Constants.ENTITY) T entity);
@Test
public void updateByid_T(){
Student student=new Student ();
student.setAge (19);
student.setEmail ("1623@163.com");
student.setName ("白居易修改测试");
student.setId (1030L);
int count = studentMapper.updateById (student);
System.out.println (count==0?"修改失败":"修改成功");
}
根据 updateWrapper 条件修改实体对象
\
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
查
根据 主键 ID 查询数据
T selectById(Serializable id);
//示例
@Test
public void selectById_T(){
Student student = studentMapper.selectById (1030L);
System.out.println (student);
}
进行批量查询
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
@Test
public void selectBatchIds_T(){
List<Student> students = studentMapper.selectBatchIds (Stream.of (1012 , 1013).collect (Collectors.toList ()));
students.forEach (System.out :: println);
}
/*
* ==> Preparing: SELECT id,name,age,email FROM student WHERE id IN ( ? , ? )
* ==> Parameters: 1012(Integer), 1013(Integer)
* <== Columns: id, name, age, email
* <== Row: 1012, 柳宗元, 18, 165@163.com
* <== Row: 1013, 柳宗元, 18, 165@163.com
* <== Total: 2
*/
根据表字段名称查询
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
@Test
public void selectByMap(){
HashMap<String, Object> map = new HashMap<> ();
map.put ("name","柳宗元");
map.put ("age","18");
List<Student> students = studentMapper.selectByMap (map);
}
/*
* ==> Preparing: SELECT id,name,age,email FROM student WHERE name = ? AND age = ?
* ==> Parameters: 柳宗元(String), 18(String)
* <== Columns: id, name, age, email
* <== Row: 1007, 柳宗元, 18, 165@163.com
* <== Row: 1008, 柳宗元, 18, 165@163.com
* <== Row: 1009, 柳宗元, 18, 165@163.com
* <== Total: 3
*/
查询记录总条数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
@Test
public void selectCount_T(){
// queryWrapper 表示实体对象封装操作类(可以为 null)
Integer integer = studentMapper.selectCount (null);
System.out.println (integer);
}
/*
* ==> Preparing: SELECT COUNT( * ) FROM student
* ==> Parameters:
* <== Columns: COUNT( * )
* <== Row: 54
* <== Total: 1
*/
查询所有记录 List
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/*
* 查询所有name=柳宗元的记录
*/
@Test
public void selectList_T(){
List<Student> students = studentMapper.selectList (new QueryWrapper<Student> ().eq ("name" , "柳宗元").);
students.forEach (System.out :: println);
}
/*
* ==> Preparing: SELECT id,name,age,email FROM student WHERE (name = ?)
* ==> Parameters: 柳宗元(String)
* <== Columns: id, name, age, email
* <== Row: 1007, 柳宗元, 18, 165@163.com
* <== Row: 1008, 柳宗元, 18, 165@163.com
* <== Row: 1009, 柳宗元, 18, 165@163.com
* <== Row: 1010, 柳宗元, 18, 165@163.com
* <== Total: 4
*/
查询所有记录 Map
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
@Test
public void selectMaps_T(){
List<Map<String, Object>> maps = studentMapper.selectMaps (new QueryWrapper<Student> ().eq ("name" , "柳宗元"));
maps.forEach (item-> {
item.forEach ((key, value)-> System.out.println (key+" --- "+value));
System.out.println ();
});
/*
* ==> Preparing: SELECT id,name,age,email FROM student WHERE (name = ?)
* ==> Parameters: 柳宗元(String)
* <== Columns: id, name, age, email
* <== Row: 1007, 柳宗元, 18, 165@163.com
* <== Row: 1008, 柳宗元, 18, 165@163.com
* <== Row: 1009, 柳宗元, 18, 165@163.com
* <== Row: 1010, 柳宗元, 18, 165@163.com
* <== Total: 4
*/
控制台打印信息
System.out.println (key+” — “+value));
/*
* name ---- 柳宗元
* id ---- 1007
* age ---- 18
* email ---- 165@163.com
*
* name ---- 柳宗元
* id ---- 1008
* age ---- 18
* email ---- 165@163.com
*
* name ---- 柳宗元
* id ---- 1009
* age ---- 18
* email ---- 165@163.com
*/
查询所有记录(但只保存第一个字段的值)
建表时,通常 id 作为首字段。可以返回所有id
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
@Test
public void selectObjs_T(){
List<Object> objects = studentMapper.selectObjs (new QueryWrapper<Student> ().likeRight ("name" , "白居易"));
objects.forEach (System.out :: println);
}
/**
* ==> Preparing: SELECT id,name,age,email FROM student WHERE (name LIKE ?)
* ==> Parameters: 白居易%(String)
* <== Columns: id, name, age, email
* <== Row: 1027, 白居易0, 19, 1623@163.com
* <== Row: 1028, 白居易1, 19, 1623@163.com
* <== Row: 1029, 白居易2, 19, 1623@163.com
* <== Row: 1030, 白居易修改测试, 19, 1623@163.com
* <== Row: 1031, 白居易4, 19, 1623@163.com
* <== Row: 1032, 白居易5, 19, 1623@163.com
* <== Row: 1033, 白居易6, 19, 1623@163.com
* <== Total: 7
*/
控制台打印数据
objects.forEach (System.out :: println);
/**
* 1027
* 1028
* 1029
* 1030
* 1031
* 1032
* 1033
*/
查询所有记录 分页 List
<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
Page<Student> studentPage = studentMapper.selectPage (new Page<> (2 , 4) ,
new QueryWrapper<Student> ().likeRight ("name" , "白居易"));
查询所有记录 分页 Map
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
@Test
public void selectMapsPage_T(){
Page<Map<String, Object>> mapPage = studentMapper.selectMapsPage (new Page<> (2 , 4) ,new QueryWrapper<Student> ().likeRight ("name" , "白居易"));
}
8.4 service层(接口方法)可以用IService<>
介绍:
使用 代码生成器 生成的 service 接口中,其继承了 IService 接口。
IService 内部进一步封装了 BaseMapper 接口的方法(当然也提供了更详细的方法)。
使用时,可以通过 生成的 mapper 类进行 CRUD 操作,也可以通过 生成的 service 的实现类进行 CRUD 操作。(当然,自定义代码执行也可)
此处简单介绍一下 IService 中封装的常用方法。
内部方法总览
方法详细介绍
汇总
【添加数据:(增)】
default boolean save(T entity); // 调用 BaseMapper 的 insert 方法,用于添加一条数据。
boolean saveBatch(Collection<T> entityList, int batchSize); // 批量插入数据
注:
entityList 表示实体对象集合
batchSize 表示一次批量插入的数据量,默认为 1000
【添加或修改数据:(增或改)】
boolean saveOrUpdate(T entity); // id 若存在,则修改, id 不存在则新增数据
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper); // 先根据条件尝试更新,然后再执行 saveOrUpdate 操作
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize); // 批量插入并修改数据
【删除数据:(删)】
default boolean removeById(Serializable id); // 调用 BaseMapper 的 deleteById 方法,根据 id 删除数据。
default boolean removeByMap(Map<String, Object> columnMap); // 调用 BaseMapper 的 deleteByMap 方法,根据 map 定义字段的条件删除
default boolean remove(Wrapper<T> queryWrapper); // 调用 BaseMapper 的 delete 方法,根据实体类定义的 条件删除对象。
default boolean removeByIds(Collection<? extends Serializable> idList); // 用 BaseMapper 的 deleteBatchIds 方法, 进行批量删除。
【修改数据:(改)】
default boolean updateById(T entity); // 调用 BaseMapper 的 updateById 方法,根据 ID 选择修改。
default boolean update(T entity, Wrapper<T> updateWrapper); // 调用 BaseMapper 的 update 方法,根据 updateWrapper 条件修改实体对象。
boolean updateBatchById(Collection<T> entityList, int batchSize); // 批量更新数据
【查找数据:(查)】
default T getById(Serializable id); // 调用 BaseMapper 的 selectById 方法,根据 主键 ID 返回数据。
default List<T> listByIds(Collection<? extends Serializable> idList); // 调用 BaseMapper 的 selectBatchIds 方法,批量查询数据。
default List<T> listByMap(Map<String, Object> columnMap); // 调用 BaseMapper 的 selectByMap 方法,根据表字段条件查询
default T getOne(Wrapper<T> queryWrapper); // 返回一条记录(实体类保存)。
Map<String, Object> getMap(Wrapper<T> queryWrapper); // 返回一条记录(map 保存)。
default int count(Wrapper<T> queryWrapper); // 根据条件返回 记录数。
default List<T> list(); // 返回所有数据。
default List<T> list(Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectList 方法,查询所有记录(返回 entity 集合)。
default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectMaps 方法,查询所有记录(返回 map 集合)。
default List<Object> listObjs(); // 返回全部记录,但只返回第一个字段的值。
default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectPage 方法,分页查询
default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectMapsPage 方法,分页查询
注:
get 用于返回一条记录。
list 用于返回多条记录。
count 用于返回记录总数。
page 用于分页查询。
【链式调用:】
default QueryChainWrapper<T> query(); // 普通链式查询
default LambdaQueryChainWrapper<T> lambdaQuery(); // 支持 Lambda 表达式的修改
default UpdateChainWrapper<T> update(); // 普通链式修改
default LambdaUpdateChainWrapper<T> lambdaUpdate(); // 支持 Lambda 表达式的修改
注:
query 表示查询
update 表示修改
Lambda 表示内部支持 Lambda 写法。
形如:
query().eq("column", value).one();
lambdaQuery().eq(Entity::getId, value).list();
update().eq("column", value).remove();
lambdaUpdate().eq(Entity::getId, value).update(entity);
增
插入一条记录
default boolean save(T entity);
@Test
public void save_T(){
Student stu=new Student ();
stu.setName ("李清照");
stu.setAge (21);
stu.setEmail ("ssm@163.com");
// 调用 BaseMapper 的 insert 方法,用于添加一条数据。
boolean save = iStudentService.save (stu);
System.out.println (save);
}
/**
* ==> Preparing: INSERT INTO student ( name, age, email ) VALUES ( ?, ?, ? )
* ==> Parameters: 李清照(String), 21(Integer), ssm@163.com(String)
* <== Updates: 1
*/
插入多条数据
boolean saveBatch(Collection<T> entityList, int batchSize);
@Test
public void saveBatch(){
List<Student> students = new ArrayList<>();
students.add (new Student ("刘咏",22,"123@123.com"));
students.add (new Student ("刘咏",22,"234@123.com"));
students.add (new Student ("刘咏",22,"345@123.com"));
students.add (new Student ("刘咏",22,"456@123.com"));
// entityList 表示实体对象集合
// batchSize 表示一次批量插入的数据量,默认为 1000
boolean b = iStudentService.saveBatch (students);
System.out.println (b);
}
/*
* ==> Preparing: INSERT INTO student ( name, age, email ) VALUES ( ?, ?, ? )
* ==> Parameters: 刘咏(String), 22(Integer), 123@123.com(String)
* ==> Parameters: 刘咏(String), 22(Integer), 234@123.com(String)
* ==> Parameters: 刘咏(String), 22(Integer), 345@123.com(String)
* ==> Parameters: 刘咏(String), 22(Integer), 456@123.com(String)
*/
删
根据主键删除数据
// 调用 BaseMapper 的 deleteById 方法,根据 id 删除数据。
default boolean removeById(Serializable id);
@Test
public void removeById_T(){
// 调用 BaseMapper 的 deleteById 方法,根据 id 删除数据。
boolean start = iStudentService.removeById (1062);
System.out.println (start);
}
根据map定义条件删除记录
default boolean removeByMap(Map<String, Object> columnMap);
@Test
public void removeByMap_T(){
boolean b = iStudentService.removeByMap (
// 删除name = 刘咏 , id = 1059 的记录
// ImmutableMap 生成的Map为不可变Map
ImmutableMap.of ("name" , "刘咏" , "id" , "1059")
);
System.out.println (b);
}
/*
* ==> Preparing: DELETE FROM student WHERE name = ? AND id = ?
* ==> Parameters: 刘咏(String), 1059(String)
* <== Updates: 1
*/
删除多条数据
default boolean removeByIds(Collection<? extends Serializable> idList);
@Test
public void removeByIds_T(){
// 用 BaseMapper 的 deleteBatchIds 方法, 进行批量删除。
boolean start = iStudentService.removeByIds (Stream.of (1065,1064,1063,1062).collect(Collectors.toList()));
System.out.println (start);
}
/*
* ==> Preparing: DELETE FROM student WHERE id IN ( ? , ? , ? , ? )
* ==> Parameters: 1065(Integer), 1064(Integer), 1063(Integer), 1062(Integer)
* <== Updates: 3
*/
根据自定义条件删除数据
default boolean remove(Wrapper<T> queryWrapper);
@Test
public void remove_T(){
boolean start = iStudentService.remove (new QueryWrapper<Student> ().eq ("id" , 1049));
System.out.println (start);
}
/**
* ==> Preparing: DELETE FROM student WHERE (id = ?)
* ==> Parameters: 1049(Integer)
* <== Updates: 1
*/
改
根据 主键 修改记录
default boolean updateById(T entity);
@Test
public void updateById_T(){
Student student = new Student ();
student.setId (1024L);
student.setName ("09:26修改测试");
// 调用 BaseMapper 的 updateById 方法,根据 ID 选择修改。
boolean b = iStudentService.updateById (student);
System.out.println (b);
/*
* ==> Preparing: UPDATE student SET name=? WHERE id=?
* ==> Parameters: 09:26修改测试(String), 1024(Long)
* <== Updates: 1
*/
}
修改多条数据
boolean updateBatchById(Collection<T> entityList, int batchSize);
// 批量更新数据
@Test
public void updateBatchById_T(){
Student student = new Student ();
student.setId (1025L);
student.setEmail ("369@124");
student.setAge (16);
student.setName ("updateBatchById_T() 修改测试");
Student student1 = new Student ();
student1.setId (1026L);
student1.setEmail ("369@124");
student1.setAge (16);
student1.setName ("updateBatchById_T() 修改测试");
Student student2 = new Student ();
student2.setId (1027L);
student2.setEmail ("369@124");
student2.setAge (16);
student2.setName ("updateBatchById_T() 修改测试");
List<Student> students = new ArrayList<> ();
students.add(student2);
students.add (student1);
students.add (student);
boolean b = iStudentService.updateBatchById (students);
System.out.println (b);
}
/*
* ==> Preparing: UPDATE student SET name=?, age=?, email=? WHERE id=?
* ==> Parameters: updateBatchById_T() 修改测试(String), 16(Integer), 369@124(String), 1027(Long)
* ==> Parameters: updateBatchById_T() 修改测试(String), 16(Integer), 369@124(String), 1026(Long)
* ==> Parameters: updateBatchById_T() 修改测试(String), 16(Integer), 369@124(String), 1025(Long)
*/
根据自定义条件修改
default boolean update(T entity, Wrapper<T> updateWrapper);
// 调用 BaseMapper 的 update 方法,根据 updateWrapper 条件修改实体对象。
@Test
public void update(){
Student student = new Student ();
student.setId (1027L);
student.setEmail ("369@124");
student.setAge (16);
student.setName ("update() 修改测试");
boolean b = iStudentService.update (student , new UpdateWrapper<Student> ().eq ("id" , "1027"));
System.out.println (b);
}
/*
* ==> Preparing: UPDATE student SET name=?, age=?, email=? WHERE (id = ?)
* ==> Parameters: update() 修改测试(String), 16(Integer), 369@124(String), 1027(String)
* <== Updates: 1
*/
查
根据主键查询
default T getById(Serializable id);
@Test
public void getById_T(){
System.out.println (iStudentService.getById (1034L));
}
/*
* ==> Preparing: SELECT id,name,age,email FROM student WHERE id=?
* ==> Parameters: 1034(Long)
* <== Columns: id, name, age, email
* <== Row: 1034, 白居易7, 19, 1623@163.com
* <== Total: 1
*/
根据主键批量查询
paramType :List
return :List
default List<T> listByIds(Collection<? extends Serializable> idList);
// 调用 BaseMapper 的 selectBatchIds 方法,批量查询数据。
@Test
public void listByIds_T(){
iStudentService.listByIds (Stream.of (1034L,1035L,1036L).collect(Collectors.toList()))
.forEach (System.out :: println);
}
/**
* ==> Preparing: SELECT id,name,age,email FROM student WHERE id IN ( ? , ? , ? )
* ==> Parameters: 1034(Long), 1035(Long), 1036(Long)
* <== Columns: id, name, age, email
* <== Row: 1034, 白居易7, 19, 1623@163.com
* <== Row: 1035, 白居易8, 19, 1623@163.com
* <== Row: 1036, 白居易9, 19, 1623@163.com
* <== Total: 3
* Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@554188ac]
* Student [Hash = 240195991, id=1034, name=白居易7, age=19, email=1623@163.com, serialVersionUID=1]
* Student [Hash = 240226743, id=1035, name=白居易8, age=19, email=1623@163.com, serialVersionUID=1]
* Student [Hash = 240257495, id=1036, name=白居易9, age=19, email=1623@163.com, serialVersionUID=1]
*/
根据Map条件查询
paramType :Map
return :List
default List<T> listByMap(Map<String, Object> columnMap);
// 调用 BaseMapper 的 selectByMap 方法,根据表字段条件查询
@Test
public void listByMap_T(){
iStudentService.listByMap (
ImmutableMap.of ("name","柳宗元","age","18")
).forEach (System.out :: println);
}
/**
* ==> Preparing: SELECT id,name,age,email FROM student WHERE name = ? AND age = ?
* ==> Parameters: 柳宗元(String), 18(String)
* <== Columns: id, name, age, email
* <== Row: 1007, 柳宗元, 18, 165@163.com
* <== Row: 1008, 柳宗元, 18, 165@163.com
* <== Row: 1009, 柳宗元, 18, 165@163.com
* ......
* <== Total: 17
* Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@553da911]
* Student [Hash = 374796304, id=1007, name=柳宗元, age=18, email=165@163.com, serialVersionUID=1]
* Student [Hash = 374826095, id=1008, name=柳宗元, age=18, email=165@163.com, serialVersionUID=1]
* Student [Hash = 374855886, id=1009, name=柳宗元, age=18, email=165@163.com, serialVersionUID=1]
*/
查找首条记录
default T getOne(Wrapper<T> queryWrapper);
public T getOne(Wrapper<T> queryWrapper, boolean throwEx);
//即getOne方法默认throwEx参数为true
default T getOne(Wrapper<T> queryWrapper) {
return this.getOne(queryWrapper, true);
}
//由返回值可知,
//当传入布尔值为true时 , 调用baseMapper.selectOne()方法。即当返回记录数不为 1 时,抛出异常。
//当传入布尔值为false时, 则取首条记录
public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
return throwEx ? this.baseMapper.selectOne(queryWrapper) : SqlHelper.getObject(this.log, this.baseMapper.selectList(queryWrapper));
}
@Test
public void getOne_T(){
//返回数据不唯一,抛出异常
System.out.println (iStudentService.getOne (new QueryWrapper<Student> ().likeRight ("name" , "白居易") ));
/**
*org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 28
*/
}
@Test
public void getOne_T(){
System.out.println (iStudentService.getOne (new QueryWrapper<Student> ().likeRight ("name" , "白居易") , false));
/**
* ==> Preparing: SELECT id,name,age,email FROM student WHERE (name LIKE ?)
* ==> Parameters: 白居易%(String)
* <== Columns: id, name, age, email
* <== Row: 1028, 白居易1, 19, 1623@163.com
* .....
* <== Row: 1055, 白居易28, 19, 1623@163.com
* <== Row: 1056, 白居易29, 19, 1623@163.com
* <== Total: 28
* Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@340d6d89]
* Warn: execute Method There are 28 results.
* Student [Hash = 240011479, id=1028, name=白居易1, age=19, email=1623@163.com, serialVersionUID=1]
*/
}
查找首条记录 Map
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 返回一条记录(map 保存)。
@Test
public void getMap_T(){
iStudentService.getMap (new QueryWrapper<Student> ().likeRight ("name" , "白居易")).forEach (
(key,value)->{
System.out.println (key+"---"+value);
}
);
}
/**
* ==> Preparing: SELECT id,name,age,email FROM student WHERE (name LIKE ?)
* ==> Parameters: 白居易%(String)
* <== Columns: id, name, age, email
* <== Row: 1028, 白居易1, 19, 1623@163.com
* <== Row: 1029, 白居易2, 19, 1623@163.com
* <== Row: 1030, 白居易修改测试, 19, 1623@163.com
* ......
* <== Total: 28
* Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@43cb5f38]
* Warn: execute Method There are 28 results.
* name---白居易1
* id---1028
* age---19
* email---1623@163.com
*/
返回记录总数(Count)
default int count(Wrapper<T> queryWrapper);
@Test
public void count_T(){
int count = iStudentService.count (new QueryWrapper<Student> ().likeRight ("name" , "白居易"));
System.out.println (count);
}
/**
* ==> Preparing: SELECT COUNT( * ) FROM student WHERE (name LIKE ?)
* ==> Parameters: 白居易%(String)
* <== Columns: COUNT( * )
* <== Row: 28
* <== Total: 1
* Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2cca611f]
* 28
*/
返回所有记录 List
default List<T> list();
@Test
public void List_T(){
iStudentService.list ().forEach (System.out :: println);
}
/**
* ==> Preparing: SELECT id,name,age,email FROM student
* ==> Parameters:
* <== Columns: id, name, age, email
*/
有条件的查询记录 List
default List<T> list(Wrapper<T> queryWrapper);
//调用 BaseMapper 的 selectList 方法,查询所有记录(返回 entity 集合)。
@Test
public void Lists_T(){
iStudentService.list (new QueryWrapper<Student> ().likeRight ("name" , "白居易"))
.forEach (System.out :: println);
}
/**
* ==> Preparing: SELECT id,name,age,email FROM student WHERE (name LIKE ?)
* ==> Parameters: 白居易%(String)
* <== Columns: id, name, age, email
* <== Row: 1028, 白居易1, 19, 1623@163.com
* <== Row: 1029, 白居易2, 19, 1623@163.com
* ......
* <== Total: 28
*/
返回所有记录 Map
default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 调用 BaseMapper 的 selectMaps 方法,查询所有记录(返回 map 集合)。
@Test
public void listMaps_T(){
iStudentService.listMaps (new QueryWrapper<Student> ().likeRight ("name" , "白居易"))
.forEach (item->item.forEach ((key,value)->{
System.out.println (key+" --- "+value);
}));
}
/**
* ==> Preparing: SELECT id,name,age,email FROM student WHERE (name LIKE ?)
* ==> Parameters: 白居易%(String)
* <== Columns: id, name, age, email
* <== Row: 1028, 白居易1, 19, 1623@163.com
* <== Row: 1029, 白居易2, 19, 1623@163.com
* <== Row: 1030, 白居易修改测试, 19, 1623@163.com
* ......
* <== Total: 28
* name --- 白居易1
* id --- 1028
* age --- 19
* email --- 1623@163.com
* name --- 白居易2
* id --- 1029
* age --- 19
* email --- 1623@163.com
* name --- 白居易修改测试
* id --- 1030
* age --- 19
* email --- 1623@163.com
*/
获取所有首字段的值 List
default List<Object> listObjs();
default List<Object> listObjs(Function<? super Object, Object>);
default List<Object> listObjs(Wrapper<Student>);
default List<Object> listObjs(Wrapper<Student>, Function<? super Object, Object>);
// 返回全部记录,但只返回第一个字段的值。
@Test
public void listObjs_T(){
iStudentService.listObjs (new QueryWrapper<Student> ().likeRight ("name" , "白居易"))
.forEach (System.out :: println);
}
/**
* ==> Preparing: SELECT id,name,age,email FROM student WHERE (name LIKE ?)
* ==> Parameters: 白居易%(String)
* <== Columns: id, name, age, email
* <== Row: 1028, 白居易1, 19, 1623@163.com
* <== Row: 1029, 白居易2, 19, 1623@163.com
* <== Row: 1030, 白居易修改测试, 19, 1623@163.com
* .....
* <== Total: 28
*
* 1028
* 1029
* .....
*/
分页查询 IPage
default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper);
// 调用 BaseMapper 的 selectPage 方法,分页查询
分页查询 IPage<Map<String,Object>>
default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper);
// 调用 BaseMapper 的 selectMapsPage 方法,分页查询
添加或修改
有则修改,无则新增
boolean saveOrUpdate(T entity);
public boolean saveOrUpdate(T entity) {
if (null == entity) {
return false;
} else {
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass);
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]);
String keyProperty = tableInfo.getKeyProperty();
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]);
Object idVal = ReflectionKit.getFieldValue(entity, tableInfo.getKeyProperty());
return !StringUtils.checkValNull(idVal) && !Objects.isNull(this.getById((Serializable)idVal)) ? this.updateById(entity) : this.save(entity);
}
}
@Test
public void saveOrUpdate_T(){
iStudentService.saveOrUpdate (new Student ("saveOrUpdate_T()",13,"13@13"));
}
/**
* ==> Preparing: INSERT INTO student ( name, age, email ) VALUES ( ?, ?, ? )
* ==> Parameters: saveOrUpdate_T()(String), 13(Integer), 13@13(String)
* <== Updates: 1
*/
先根据条件尝试更新,然后再执行 saveOrUpdate 操作
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper); // 先根据条件尝试更新,然后再执行 saveOrUpdate 操作
@Test
public void saveOrUpdate_T2(){
iStudentService.saveOrUpdate (new Student ("saveOrUpdate_T()",13,"13@13"),
new UpdateWrapper<Student> ().eq ("age",14).likeRight ("name","白居易"));
}
/**
* ==> Preparing: UPDATE student SET name=?, age=?, email=? WHERE (age = ? AND name LIKE ?)
* ==> Parameters: saveOrUpdate_T()(String), 13(Integer), 13@13(String), 14(Integer), 白居易%(String)
* <== Updates: 1
*/
批量插入或修改数据
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass);
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]);
String keyProperty = tableInfo.getKeyProperty();
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]);
return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, batchSize, (sqlSession, entity) -> {
Object idVal = ReflectionKit.getFieldValue(entity, keyProperty);
return StringUtils.checkValNull(idVal) || CollectionUtils.isEmpty(sqlSession.selectList(this.getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
}, (sqlSession, entity) -> {
ParamMap<T> param = new ParamMap();
param.put("et", entity);
sqlSession.update(this.getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
});
}
@Test
public void saveOrUpdateBatch_T(){
Student student = new Student ();
student.setId (1025L);
student.setEmail ("369@124");
student.setAge (16);
student.setName ("saveOrUpdateBatch_T() 修改测试");
Student student1 = new Student ();
student1.setId (1026L);
student1.setEmail ("369@124");
student1.setAge (16);
student1.setName ("saveOrUpdateBatch_T() 修改测试");
Student student2 = new Student ();
student2.setId (1200L);
student2.setEmail ("369@124");
student2.setAge (16);
student2.setName ("saveOrUpdateBatch_T() 修改测试");
Student student4 = new Student ();
student2.setEmail ("369@124");
student2.setAge (16);
student2.setName ("saveOrUpdateBatch_T() 修改测试");
List<Student> students = new ArrayList<> ();
students.add(student2);
students.add (student1);
students.add (student);
//添加student4后报错,可能id不能为null?但是saveOrUpdate中为空则执行插入
//students.add (student4);
boolean b = iStudentService.saveOrUpdateBatch (students);
}
/**
* ==> Preparing: SELECT id,name,age,email FROM student WHERE id=?
* ==> Parameters: 1200(Long)
* <== Total: 0
* ==> Preparing: INSERT INTO student ( name, age, email ) VALUES ( ?, ?, ? )
* ==> Parameters: saveOrUpdateBatch_T() 修改测试(String), 16(Integer), 369@124(String)
* ==> Preparing: SELECT id,name,age,email FROM student WHERE id=?
* ==> Parameters: 1026(Long)
* <== Columns: id, name, age, email
* <== Row: 1026, saveOrUpdateBatch_T() 修改测试, 16, 369@124
* <== Total: 1
* ==> Preparing: UPDATE student SET name=?, age=?, email=? WHERE id=?
* ==> Parameters: saveOrUpdateBatch_T() 修改测试(String), 16(Integer), 369@124(String), 1026(Long)
* ==> Preparing: SELECT id,name,age,email FROM student WHERE id=?
* ==> Parameters: 1025(Long)
* <== Columns: id, name, age, email
* <== Row: 1025, saveOrUpdateBatch_T() 修改测试, 16, 369@124
* <== Total: 1
* ==> Preparing: UPDATE student SET name=?, age=?, email=? WHERE id=?
* ==> Parameters: saveOrUpdateBatch_T() 修改测试(String), 16(Integer), 369@124(String), 1025(Long)
*/
8.5 链式调用
default QueryChainWrapper<T> query(); // 普通链式查询
default LambdaQueryChainWrapper<T> lambdaQuery(); // 支持 Lambda 表达式的修改
default UpdateChainWrapper<T> update(); // 普通链式修改
default LambdaUpdateChainWrapper<T> lambdaUpdate(); // 支持 Lambda 表达式的修改
query().eq("column", value).one();
lambdaQuery().eq(Entity::getId, value).list();
update().eq("column", value).remove();
lambdaUpdate().eq(Entity::getId, value).update(entity);
8.6 各操作对应SQL语句参考
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.baomidou.mybatisplus.core.enums;
public enum SqlMethod {
INSERT_ONE("insert", "插入一条数据(选择字段插入)", "<script>\nINSERT INTO %s %s VALUES %s\n</script>"),
UPSERT_ONE("upsert", "Phoenix插入一条数据(选择字段插入)", "<script>\nUPSERT INTO %s %s VALUES %s\n</script>"),
DELETE_BY_ID("deleteById", "根据ID 删除一条数据", "<script>\nDELETE FROM %s WHERE %s=#{%s}\n</script>"),
DELETE_BY_MAP("deleteByMap", "根据columnMap 条件删除记录", "<script>\nDELETE FROM %s %s\n</script>"),
DELETE("delete", "根据 entity 条件删除记录", "<script>\nDELETE FROM %s %s %s\n</script>"),
DELETE_BATCH_BY_IDS("deleteBatchIds", "根据ID集合,批量删除数据", "<script>\nDELETE FROM %s WHERE %s IN (%s)\n</script>"),
LOGIC_DELETE_BY_ID("deleteById", "根据ID 逻辑删除一条数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
LOGIC_DELETE_BY_MAP("deleteByMap", "根据columnMap 条件逻辑删除记录", "<script>\nUPDATE %s %s %s\n</script>"),
LOGIC_DELETE("delete", "根据 entity 条件逻辑删除记录", "<script>\nUPDATE %s %s %s %s\n</script>"),
LOGIC_DELETE_BATCH_BY_IDS("deleteBatchIds", "根据ID集合,批量逻辑删除数据", "<script>\nUPDATE %s %s WHERE %s IN (%s) %s\n</script>"),
UPDATE_BY_ID("updateById", "根据ID 选择修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
UPDATE("update", "根据 whereEntity 条件,更新记录", "<script>\nUPDATE %s %s %s %s\n</script>"),
LOGIC_UPDATE_BY_ID("updateById", "根据ID 修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
SELECT_BY_ID("selectById", "根据ID 查询一条数据", "SELECT %s FROM %s WHERE %s=#{%s} %s"),
SELECT_BY_MAP("selectByMap", "根据columnMap 查询一条数据", "<script>SELECT %s FROM %s %s\n</script>"),
SELECT_BATCH_BY_IDS("selectBatchIds", "根据ID集合,批量查询数据", "<script>SELECT %s FROM %s WHERE %s IN (%s) %s</script>"),
SELECT_ONE("selectOne", "查询满足条件一条数据", "<script>%s SELECT %s FROM %s %s %s\n</script>"),
SELECT_COUNT("selectCount", "查询满足条件总记录数", "<script>%s SELECT COUNT(%s) FROM %s %s %s\n</script>"),
SELECT_LIST("selectList", "查询满足条件所有数据", "<script>%s SELECT %s FROM %s %s %s\n</script>"),
SELECT_PAGE("selectPage", "查询满足条件所有数据(并翻页)", "<script>%s SELECT %s FROM %s %s %s\n</script>"),
SELECT_MAPS("selectMaps", "查询满足条件所有数据", "<script>%s SELECT %s FROM %s %s %s\n</script>"),
SELECT_MAPS_PAGE("selectMapsPage", "查询满足条件所有数据(并翻页)", "<script>\n %s SELECT %s FROM %s %s %s\n</script>"),
SELECT_OBJS("selectObjs", "查询满足条件所有数据", "<script>%s SELECT %s FROM %s %s %s\n</script>");
private final String method;
private final String desc;
private final String sql;
private SqlMethod(String method, String desc, String sql) {
this.method = method;
this.desc = desc;
this.sql = sql;
}
public String getMethod() {
return this.method;
}
public String getDesc() {
return this.desc;
}
public String getSql() {
return this.sql;
}
}
注:数据库引入数据
/*
Navicat Premium Data Transfer
Source Server : imooc
Source Server Type : MySQL
Source Server Version : 80021
Source Host : localhost:3306
Source Schema : mybatisplus_demo
Target Server Type : MySQL
Target Server Version : 80021
File Encoding : 65001
Date: 23/06/2022 11:34:24
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID,学号',
`name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名',
`age` int NULL DEFAULT NULL COMMENT '年龄',
`email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`) USING BTREE,
INDEX `id`(`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1063 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1002, 'Jack', 20, 'test2@baomidou.com');
INSERT INTO `student` VALUES (1003, 'Tom', 28, 'test3@baomidou.com');
INSERT INTO `student` VALUES (1004, 'Sandy', 21, 'test4@baomidou.com');
INSERT INTO `student` VALUES (1005, 'Billie', 24, 'test5@baomidou.com');
INSERT INTO `student` VALUES (1007, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1008, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1009, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1010, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1011, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1012, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1013, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1014, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1015, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1016, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1017, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1018, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1019, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1020, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1021, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1022, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1023, '柳宗元', 18, '165@163.com');
INSERT INTO `student` VALUES (1024, '09:26修改测试', 18, '165@163.com');
INSERT INTO `student` VALUES (1025, 'saveOrUpdateBatch_T() 修改测试', 16, '369@124');
INSERT INTO `student` VALUES (1026, 'saveOrUpdateBatch_T() 修改测试', 16, '369@124');
INSERT INTO `student` VALUES (1027, 'saveOrUpdateBatch_T() 修改测试', 16, '369@124');
INSERT INTO `student` VALUES (1028, '白居易1', 19, '1623@163.com');
INSERT INTO `student` VALUES (1029, '白居易2', 19, '1623@163.com');
INSERT INTO `student` VALUES (1030, '白居易修改测试', 19, '1623@163.com');
INSERT INTO `student` VALUES (1031, 'saveOrUpdate_T()', 13, '13@13');
INSERT INTO `student` VALUES (1032, '白居易5', 19, '1623@163.com');
INSERT INTO `student` VALUES (1033, '白居易6', 19, '1623@163.com');
INSERT INTO `student` VALUES (1034, '白居易7', 19, '1623@163.com');
INSERT INTO `student` VALUES (1035, '白居易8', 19, '1623@163.com');
INSERT INTO `student` VALUES (1036, '白居易9', 19, '1623@163.com');
INSERT INTO `student` VALUES (1037, '白居易10', 19, '1623@163.com');
INSERT INTO `student` VALUES (1038, '白居易11', 19, '1623@163.com');
INSERT INTO `student` VALUES (1039, '白居易12', 19, '1623@163.com');
INSERT INTO `student` VALUES (1040, '白居易13', 19, '1623@163.com');
INSERT INTO `student` VALUES (1041, '白居易14', 19, '1623@163.com');
INSERT INTO `student` VALUES (1042, '白居易15', 19, '1623@163.com');
INSERT INTO `student` VALUES (1043, '白居易16', 19, '1623@163.com');
INSERT INTO `student` VALUES (1044, '白居易17', 19, '1623@163.com');
INSERT INTO `student` VALUES (1045, '白居易18', 19, '1623@163.com');
INSERT INTO `student` VALUES (1046, '白居易19', 19, '1623@163.com');
INSERT INTO `student` VALUES (1047, '白居易20', 19, '1623@163.com');
INSERT INTO `student` VALUES (1048, '白居易21', 19, '1623@163.com');
INSERT INTO `student` VALUES (1050, '白居易23', 19, '1623@163.com');
INSERT INTO `student` VALUES (1051, '白居易24', 19, '1623@163.com');
INSERT INTO `student` VALUES (1052, '白居易25', 19, '1623@163.com');
INSERT INTO `student` VALUES (1053, '白居易26', 19, '1623@163.com');
INSERT INTO `student` VALUES (1054, '白居易27', 19, '1623@163.com');
INSERT INTO `student` VALUES (1055, '白居易28', 19, '1623@163.com');
INSERT INTO `student` VALUES (1056, '白居易29', 19, '1623@163.com');
INSERT INTO `student` VALUES (1057, '李清照', 21, 'ssm@163.com');
INSERT INTO `student` VALUES (1058, '李清照', 21, 'ssm@163.com');
INSERT INTO `student` VALUES (1066, '刘咏', 22, '456@123.com');
INSERT INTO `student` VALUES (1067, '李清照', 21, 'ssm@163.com');
INSERT INTO `student` VALUES (1068, '刘咏', 22, '123@123.com');
INSERT INTO `student` VALUES (1069, '刘咏', 22, '234@123.com');
INSERT INTO `student` VALUES (1070, '刘咏', 22, '345@123.com');
INSERT INTO `student` VALUES (1071, '刘咏', 22, '456@123.com');
INSERT INTO `student` VALUES (1072, 'saveOrUpdate_T()', 13, '13@13');
INSERT INTO `student` VALUES (1073, 'saveOrUpdate_T()', 13, '13@13');
INSERT INTO `student` VALUES (1075, 'saveOrUpdateBatch_T() 修改测试', 16, '369@124');
SET FOREIGN_KEY_CHECKS = 1;