一:MyBatis-Plus简介
二:MyBatis-Plus入门案例(SpringBoot整合MyBatis-Plus)
1.创建新模块,选择Spring初始化,并配置相关信息
2.选择当前模块需要的依赖(只需要MySQL Driver)
3.在pom.xml文件中添加MyBatyis-Plus起步依赖和Druid数据库连接池依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
4.创建数据库和数据表以及数据
create database if not exists mybatisplus_db character set utf8;
use mybatisplus_db;
CREATE TABLE user (
id bigint(20) primary key auto_increment,
name varchar(32) not null,
password varchar(32) not null,
age int(3) not null ,
tel varchar(32) not null
);
insert into user values(null,'tom','123456',12,'12345678910');
insert into user values(null,'jack','123456',8,'12345678910');
insert into user values(null,'jerry','123456',15,'12345678910');
insert into user values(null,'tom','123456',9,'12345678910');
insert into user values(null,'snake','123456',28,'12345678910');
insert into user values(null,'张益达','123456',22,'12345678910');
insert into user values(null,'张大炮','123456',16,'12345678910');
5.创建实体类
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
//自行添加getter、setter、toString()等方法
}
6.在application,yml中配置数据库连接信息
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
username: root
password: root
7.定义数据层接口,这个接口继承BaseMapper
@Mapper
public interface UserDao extends BaseMapper<User> {
}
8.在service类中或者测试类注入数据层接口,测试查询所有的功能
@SpringBootTest
public class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
List<User> userList = userDao.selectList(null);
System.out.println(userList);
}
}
三:基于MyBatis-Plus实现CRUD和分页功能, 完成标准数据层开发
MyBatis-Plus提供了许多接口来完成增删改查操作
下面我们来对比一下之前我们用MyBatis自己编写的接口和MyBatis-Plus提供的接口
这个小节案例和入门案例的操作步骤一致,不同点就在于测试类的编写,所以这里仅展现测试类中的代码
1.基于MyBatis-Plus完成标准数据层开发,实现CRUD功能
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testSave() {
User user = new User();
user.setName("张三");
user.setPassword("123456789");
user.setAge(15);
user.setTel("177777888888");
userDao.insert(user);
}
@Test
void testDelete(){
userDao.deleteById(1691295532225380353L);
}
@Test
void testUpdate(){
User user = new User();
user.setId(1L);
user.setName("Tom888");
user.setPassword("dom222");
userDao.updateById(user);
}
@Test
void testGetById(){
User user = userDao.selectById(2L);
System.out.println(user);
}
@Test
void testGetAll(){
List<User> users = userDao.selectList(null);
System.out.println(users);
}
}
2.基于MyBatis-Plus完成标准数据层开发,实现分页功能
-1-设置分页拦截器
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//1 创建MybatisPlusInterceptor拦截器对象
MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
//2 添加分页拦截器
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mpInterceptor;
}
}
-2-在测试类中创建IPage分页对象,设置分页参数,执行分页查询
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetByPage(){
// 创建IPage分页对象,设置分页参数
IPage<User> page = new Page<>(2, 3);
//2 执行分页查询
userDao.selectPage(page,null);//queryWrapper为空即不设置查询条件
//3 获取分页结果
System.out.println("当前页码值: "+ page.getCurrent());
System.out.println("每页显示数: "+page.getSize());
System.out.println("总共的页数: "+page.getPages());
System.out.println("总共的数据条数: "+page.getTotal());
System.out.println("当前页的数据为: "+page.getRecords());
}
}
四:基于MyBatis-Plus完成复杂条件查询(DQL编程控制)
基于MyBatis-Plus将复杂的SQL查询条件进行了封装(Wrapper<T>),使用编程的形式完成查询条件的组合
常见的MyBatis-Plus查询接口有:
0.条件查询案例环境准备
create database if not exists mybatisplus_db character set utf8;
use mybatisplus_db;
CREATE TABLE tbl_user (
id bigint(20) primary key auto_increment,
name varchar(32) not null,
pwd varchar(32) not null,
age int(3) not null ,
tel varchar(32) not null
);
insert into user values(null,'tom','123456',12,'12345678910');
insert into user values(null,'jack','123456',8,'12345678910');
insert into user values(null,'jerry','123456',15,'12345678910');
insert into user values(null,'tom','123456',9,'12345678910');
insert into user values(null,'snake','123456',28,'12345678910');
insert into user values(null,'张益达','123456',22,'12345678910');
insert into user values(null,'张大炮','123456',16,'12345678910');
@Data
@TableName("tbl_user") //在模型类上方,使用@TableName注解,通过value属性,设置当前类对应的数据库表名称。
public class User {
private Long id;
private String name;
@TableField(value="pwd",select = false)//使用@TableField属性注解,通过value属性,设置当前属性对应的数据库表中的字段关系;通过select属性:设置该属性是否参与查询
private String password;
private Integer age;
private String tel;
}
@Mapper
public interface UserDao extends BaseMapper<User> {
}
注:Lombok工具的使用
Lombok,一个Java类库,提供了一组注解,简化POJO实体类开发,常用注解是@Data,这个注解为当前实体类在编译期设置对应的get/set方法,无参/无参构造方法,toString方法,hashCode方法,equals方法等,也就是在实体类上加了这个注解就不用手动生成get/set等方法了
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
1.条件查询中常见的条件构建方式
-1-常规条件构建格式
//方式一:常规格式
QueryWrapperr<User> qw = new QueryWrapperr<User>();
qw.lt("age",18); //条件为年龄小于18
//List<User> userlist = userDao.selectList(qw);
//System.out.println(userlist);
-2-lamda格式条件构建格式
//方式二:lambda格式(QueryWrapper.lambda())
QueryWrapper<User> qw = new QueryWrapper<User>();
qw.lambda().lt(User::getAge,10);//条件为年龄小于10
//List<User> users = userDao.selectList(qw);
//System.out.println(users);
-3-lambda格式条件构建格式 (推荐使用)
//方式三:lambda格式(LambdaQueryWrapper), 更推荐的方式
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 10);//条件为年龄小于10
//List<User> userList = userDao.selectList(lqw);
//System.out.println(userList);
2.常见的单条件查询
-1- eq匹配
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//等同于=
lqw.eq(User::getName, "Jerry").eq(User::getPassword, "jerry");
User loginUser = userDao.selectOne(lqw);
System.out.println(loginUser);
-2- lt匹配
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
-3- le匹配
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.le(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
-4- gt匹配
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
-5- ge匹配
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.ge(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
-6- between匹配
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//范围查询 lt le gt ge eq between
lqw.between(User::getAge, 10, 30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
-7- like匹配
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//模糊匹配 like
lqw.likeLeft(User::getName, "J");
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
3.多条件查询
-1-两个条件同时满足(并且关系)
//并且关系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//并且关系:10到30岁之间
lqw.lt(User::getAge, 30).gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
-2-两个条件满足其一(或者关系)
//或者关系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//或者关系:小于10岁或者大于30岁
lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
4.条件查询中追加对于空值的处理(实现动态查询)
-1-使用if条件语句
@Test
//使用if条件语句进行空值的处理
void testConditionNotNull1() {
Integer minAge = 10;
Integer maxAge = null;
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
if (minAge != null) {
lqw.gt(User::getAge, minAge);
}
if (maxAge != null) {
lqw.lt(User::getAge, maxAge);
}
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);
}
-2-使用条件参数控制
@Test
//使用条件参数控制进行空值的处理(不使用链式编程)
void testConditionNotNull2() {
Integer minAge = null;
Integer maxAge = 20;
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.gt(minAge != null, User::getAge, minAge);
lqw.lt(maxAge != null, User::getAge, maxAge);
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);
}
@Test
//使用条件参数控制进行空值的处理(使用链式编程)
void testConditionNotNull3() {
Integer minAge = null;
Integer maxAge = 20;
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.gt(minAge != null, User::getAge, minAge)
.lt(maxAge != null, User::getAge, maxAge);
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);
}
5.查询投影
-1-查询模型类中部分属性
@Test
void testSelectCast1() {
//查询部分属性而不是模型类中所有的属性
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.select(User::getId, User::getName, User::getAge);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
}
-2-查询模型类中未定义的属性
@Test
void testSelectCast2() {
//查询模型类中没有的属性
QueryWrapper<User> qw = new QueryWrapper<User>();
//qw.select("count(*) as count,tel");
qw.select("count(*) as count","tel");
qw.groupBy("tel");
List<Map<String, Object>> userList = userDao.selectMaps(qw);
System.out.println(userList);
}
六:DML控制
1.id生成策略控制
-1-常见id生成策略
-2-模型类中添加id生成策略的方式
正如上图所示: 将@TableId注解定义在模型类中用于表示主键的属性上方,type属性设置主键属性的生成策略,值参照IdType枚举值
-3-在application.yml文件中全局配置id生成策略的方式
mybatis-plus:
global-config:
db-config:
id-type: assign_id
table-prefix: tbl_ # 将这个id生成策略应用到所有以tbl_开头的表中
2.批量删除
@Test
void testBatchDelete() {
ArrayList<Long> list = new ArrayList<>();
list.add(6L);
list.add(5L);
userDao.deleteBatchIds(list);
}
3.批量查询
@Test
void testBatchSelect(){
ArrayList<Long> list = new ArrayList<>();
list.add(1L);
list.add(2L);
list.add(3L);
userDao.selectBatchIds(list);
}
4.逻辑删除
--定义
删除数据时并不是真的删除数据,而是将新增一个逻辑删除标记字段,删除时设置该字段为不可用字段,数据保留在数据库中
--步骤
-1-添加逻辑删除标记字段
-2-实体类中添加对应字段,并在该字段上添加@TableLogic设定当前字段为逻辑删除标记字段
@Data
@TableName("tbl_user")
public class User {
private Long id;
private String name;
@TableField(value="pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableLogic(value="0",delval = "1")
private Integer deleted; //逻辑删除字段,标记当前记录是否被删除,未删除为0,删除为1
}
-3- 在application.yml文件中配置逻辑删除字段名及字段值
mybatis-plus: global-config: db-config: table-prefix: tbl_ # 逻辑删除字段名 logic-delete-field: deleted # 逻辑删除字面值:未删除为0 logic-not-delete-value: 0 # 逻辑删除字面值:删除为1 logic-delete-value: 1
-4- 编写测试代码
@Test
void testUpdate(){
User user = new User();
user.setId(1L);
user.setName("Tom888");
user.setPassword("dom222");
user.setDeleted(1);
userDao.updateById(user);
}
七:实体类与表映射相关问题
1.实体类属性和表字段名称不一致问题解决方案
在模型类属性上添加@TableField注解,通过value属性,设置两者之间的对应关系
@Data
public class User {
private Long id;
private String name;
@TableField(value="pwd")//使用@TableField属性注解,通过value属性,设置当前属性对应的数据库表中的字段关系;
private String password;
private Integer age;
private String tel;
}
2.实体类中添加了数据库中中未定义的属性
在模型类属性上,添加@TableField注解,通过exist属性,设置该属性为false即可(默认为true)
@Data
public class User {
private Long id;
private String name;
@TableField(value="pwd")//使用@TableField属性注解,通过value属性,设置当前属性对应的数据库表中的字段关系;
private String password;
private Integer age;
private String tel;
@TableField(exist = false) //使用@TableField注解,通过exist属性,设置属性在数据库表字段中是否存在,默认为true
private Integer online;
}
3.在模型类中设置对应表的映射关系
在模型类上添加注解@TableName,通过value属性,设置当前类对应的数据表名称
@Data
@TableName("tbl_user") //在模型类上方,使用@TableName注解,通过value属性,设置当前类对应的数据库表名称。
public class User {
private Long id;
private String name;
@TableField(value="pwd")//使用@TableField属性注解,通过value属性,设置当前属性对应的数据库表中的字段关系;
private String password;
private Integer age;
private String tel;
@TableField(exist = false) //使用@TableField注解,通过exist属性,设置属性在数据库表字段中是否存在,默认为true
private Integer online;
}
4.在模型类中设置字段是否参与查询
在模型类属性上方,使用@TableField注解,通过select属性的值设置是否参与查询,true为参与查询,false为不参与查询
@Data
@TableName("tbl_user") //在模型类上方,使用@TableName注解,通过value属性,设置当前类对应的数据库表名称。
public class User {
private Long id;
private String name;
@TableField(value="pwd",select = false)//使用@TableField属性注解,通过value属性,设置当前属性对应的数据库表中的字段关系;通过select属性:设置该属性是否参与查询
private String password;
private Integer age;
private String tel;
/@TableField(exist = false) //使用@TableField注解,通过exist属性,设置属性在数据库表字段中是否存在,默认为true
private Integer online;
}
八:日志控制
1.开启MyBatisPlus日志
# 开启mp的日志(输出到控制台)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.取消Spring初始化日志打印
在resources下新建一个logback.xml文件,名称固定,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
</configuration>
3.取消SpringBoot启动banner
spring:
main:
banner-mode: off # 关闭SpringBoot启动图标(banner)
4.取消MyBatis-plus启动banner
# mybatis-plus日志控制台输出
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: off # 关闭mybatisplus启动图标
九:配置文件
在springboot项目配置文件中可以配置如下内容
mybatis-plus: type-aliases-package: com.**.entity mapper-locations: classpath:/**/xml/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true call-setters-on-nulls: true global-config: id-type: auto field-strategy: NOT_EMPTY db-type: MYSQL logic-not-delete-value: 0 logic-delete-value: 1 table-prefix: t_
mybatis-plus:
# 包扫描路径(当前项目的实体类所在位置。别名包扫描路径,通过该属性可以给包中的类注册别名,多个路径用逗号分割)
type-aliases-package: com.**.entity
# xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
mapper-locations: classpath:/**/xml/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
# 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
# 允许在resultType="map"时映射null值
# call-setters-on-nulls: true
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用(包括执行结果)
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
# db-config:
# # 主键类型 AUTO:"数据库ID自增"
# # INPUT:"用户输入ID",
# # ID_WORKER:"全局唯一ID (数字类型唯一ID)",
# # UUID:"全局唯一ID UUID";
# id-type: auto
# # 字段策略 IGNORED:"忽略判断" NOT_NULL:"非 NULL 判断") NOT_EMPTY:"非空判断"
# field-strategy: NOT_EMPTY
# # 数据库类型
# db-type: MYSQL
# # 逻辑删除配置
# # 删除前
# logic-not-delete-value: 0
# # 删除后
# logic-delete-value: 1
# # 数据库表名的前缀
# table-prefix: t_