简介
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
润物无声
只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
效率至上
只需简单配置,即可快速进行 CRUD 操作,从而节省大量时间。
丰富功能
热加载、代码生成、分页、性能分析等功能一应俱全。
1、创建数据库
CREATE TABLE USER
(
id BIGINT(20)NOT NULL COMMENT '主键ID',
NAME VARCHAR(30)NULL DEFAULT NULL COMMENT '姓名',
age INT(11)NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50)NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email)VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
2、创建项目
初始化工程:使用 Spring Initializr 快速初始化一个 Spring Boot 工程
引入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
3、编写代码
在 application.properties 配置文件中添加 MySQL 数据库的相关配置
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=root
注意
1、这里的 url 使用了 ?serverTimezone=GMT%2B8 后缀,因为8.0版本的jdbc驱动需要添加这个后缀,否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more
2、这里的 driver-class-name 使用了 com.mysql.cj.jdbc.Driver ,在 jdbc 8 中 建议使用这个驱动,否则运行测试用例的时候会有 WARN 信息
在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹
package com.example.demomptest;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.demomptest.mapper")
public class DemomptestApplication {
public static void main(String[] args) {
SpringApplication.run(DemomptestApplication.class, args);
}
}
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
之前我们编写Mapper需要写接口和SQL语句,使用Mybatis-Plus直接使其继承BaseMapper接口即可。
package com.example.demomptest.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demomptest.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface Usermapper extends BaseMapper<User> {
}
package com.example.demomptest;
import com.example.demomptest.entity.User;
import com.example.demomptest.mapper.Usermapper;
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 DemomptestApplicationTests {
@Autowired
private Usermapper usermapper;
//测试查找所有用户
@Test
public void findall() {
List<User> user = usermapper.selectList(null);
System.out.println(user);
}
}
查看SQL输出日志
在 application.properties 中编写,这样就可以在控制台看到具体SQL和操作。
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
4.主键策略
我们在测试插入操作时发现,我们不定义User_ID,系统会帮我们创建一个19位的id值,这是为什么呢?比如:
这里就用到了Mybatis-plus的主键策略
MyBatis-Plus默认的主键策略是:ASSIGN_ID,这个策略就是指ID是随机的十九位数
@TableId(type = IdType.ASSIGN_ID)
private Long id;
其他主键配置:
AUTO
:数据库主键自增
INPUT
:用户自定义id
NONE
:未设置主键类型
常用注解
@TableName("表名")
当表名与实体类名不一致时,可以在实体类上加入@TableName()声明
@TableId
声明属性为表中的主键(若属性名称不为默认id)
@TableFieId("字段")
当实体类属性与表字段不一致时,可以用来声明
5、自动填充和乐观锁
什么是自动填充?
有些表中会有更新时间update_time、创建时间create_time、更新人或者创建人这些字段。
每次对数据进行新增、删除、修改时都需要对这些字段进行设置。传统的做法是在进行这些操作前,对实体的字段进行set设置,然后再进行操作。这种做法不仅容易忘记导致出错、而且代码会显得特别冗余。
虽然新增时间和修改时间可以使用数据库的时间,但是新增人和修改人就不能使用这样的功能。
所以 MyBatis-Plus 就提供自动填充的功能,帮助自定设置这些字段的值,提升开发效率,代码也会显得特别优雅。
自动填充有两种实现方式,一种数据库层面实现,一种编程实现
1、数据库层面实现
在User表中添加datetime类型的新的字段 create_time、update_time
2、实体类层面实现
实体上增加字段并添加自动填充注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
package com.example.demomptest.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
// mp执行添加操作,这个方法执行
@Override
public void insertFill(MetaObject metaObject){
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
this.setFieldValByName("version",1,metaObject);
}
// mp执行修改操作,这个方法执行
@Override
public void updateFill(MetaObject metaObject){
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
乐观锁
场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
乐观锁实现方式
1、取出记录时,获取当前version
2、更新时,带上这个version
3、执行更新时, set version = newVersion where version = oldVersion
4、如果version不对,就更新失败
特别说明
支持的数据类型只有:int、Integer、long、Long、Date、Timestamp、LocalDateTime
整数类型下 newVersion = oldVersion + 1
乐观锁实现流程
@Version
private Integer version;
创建包config,创建文件MybatisPlusConfig.java
@Configuration
@MapperScan("com.atguigu.demomptest.mapper")
public class MpConfig {
/**
* 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
条件构造器(Wrapper)
场景:编写一些复杂的SQL语句需要用到Wrapper
查找 age >= 22 的 user
// Wrapper测试
@Test
public void testWrapper(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.ge("age",22);
List<User> users = usermapper.selectList(queryWrapper);
System.out.println(users);
}
查找 name = Lucy 的用户
// 测试eq
@Test
public void testWrapper(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name","Lucy");
User user = usermapper.selectOne(queryWrapper);
System.out.println(user);
}
测试年龄在18 到 22 的用户
// 测试between
@Test
public void testWrapper(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.between("age",18,22);
List<User> users = usermapper.selectList(queryWrapper);
System.out.println(users);
}
测试姓名含张的用户
// 测试like
@Test
public void testWrapper(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name","张");
List<User> users = usermapper.selectList(queryWrapper);
System.out.println(users);
}
测试年龄降序排列
// 年龄倒序排列
@Test
public void testSelectListOrderBy() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age", "id");
List<User> users = usermapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
查询方式
查询方式 | 说明 |
---|---|
setSqlSelect | 设置 SELECT 查询字段 |
where | WHERE 语句,拼接 + WHERE 条件 |
eq | 等于= |
ne | 不等于<> |
gt | 大于> |
ge | 大于等于>= |
lt | 小于< |
le | 小于等于<= |
like | 模糊查询 LIKE |
notLike | 模糊查询 NOT LIKE |
in | IN 查询 |
notIn | NOT IN 查询 |
isNull | NULL 值查询 |
isNotNull | IS NOT NULL |
groupBy | 分组 GROUP BY |
having | HAVING 关键词 |
groupBy | 分组 GROUP BY |
orderBy | 排序 ORDER BY |
orderByAsc | 升序排序 |
orderByDesc | 降序排序 |
between | BETWEEN 条件语句 |
notBetween | NOTBETWEEN 条件语句 |