简介
MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。<br /> 官网: [https://baomidou.com/guide/](https://baomidou.com/guide/)
入门案例
地址:[https://mp.baomidou.com/guide/quick-start.html#](https://mp.baomidou.com/guide/quick-start.html#)初始化工程<br />步骤1:建库建表
create database rbac;
use rbac;
create table t_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 t_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:创建springboot项目
步骤3:引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<!-- mybatis-plus 是个人开发者发布的,并非官方发布! -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</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>
注意:MP的starter依赖中已经包含了mybatis及mybatis-spring组件,不要再次引入,避免出现jar包冲突问题。
步骤4:配置文件
server:
port: 8888
servlet:
context-path: /mp
spring:
application:
name: mp
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/rbac?characterEncoding=UTF-8
username: root
password: root
步骤5:创建实体类及mapper接口
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
@TableName("t_user") //实体类名与数据表名不一致时,使用该注解
public class User implements Serializable {
private Long id;
private String name;
private Integer age;
private String email;
}
public interface UserMapper extends BaseMapper<User> {
//对于非复杂CRUD操作而言,BaseMapper接口中已经全部做相关定义
//使用时只需要调用相关方法即可完成相关功能,无需书写SQL映射文件
//对于要实现特别复杂的业务操作时,如果BaseMapper接口中定义的方法不足以解决相应需求
//可在UserMapper中自定义方法,按照正常的mybatis操作方式去解决即可
//一般来说,掌握BaseMapper中的方法即可完成绝大部分的业务,自定义方法的操作应用比较少
}
步骤6:在启动类上扫描Mapper所在包,注册到spring容器。
@MapperScan("com.woniu.mapper")
步骤7:测试
@SpringBootTest class MybatisPlusApplicationTests {
// 继承了BaseMapper,所有的方法都来自父类
// 我们也可以编写自己的扩展方法!
@Autowired private UserMapper userMapper;
@Test void contextLoads() {
// 参数是一个 Wrapper,条件构造器,查询全部时无需设置条件--->null
// 查询全部用户
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
查看执行日志
修改配置文件:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
CRUD
插入操作 : insert
@Test
public void testInsert(){
User user = new User();
user.setName("张三")
.setAge(30)
.setEmail("zhangsan@163.com");
int count = userMapper.insert(user);//受影响的行数
System.out.println(user.getId()); //mybatis-plus实现了主键自动回填
}
主键生成策略
官网:[https://mp.baomidou.com/guide/annotation.html#tableid](https://mp.baomidou.com/guide/annotation.html#tableid)
指定主键生成策略
使用@tableid注解实现。
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
@TableName("t_user")//表示当前类映射的数据库表名
public class User {
@TableId(type = IdType.AUTO) //表示将主键设置为自增长,需要数据库表主键为auto_increment
private Long id;
private String name;
private Integer age;
private String email;
}
更新操作:update
@Test
public void testUpdate(){
User user = new User();
user.setId(1L);
user.setAge(30);
userMapper.updateById(user);
}
自动填充:fill
阿里巴巴开发手册中明确规定,所有的数据库表上必须存在gmt_create、gmt_modifified字段,用于描述当前表数据的创建时间和修改时间。(gmt:前缀用于提醒开发者应考虑时区问题,开发者的本地时需要转换成世界时之后再存到字段里面去,这样数据库存储的时间就不会因为时区乱掉。)<br />gmt_create、gmt_modifified字段不应该被手动赋值,应该由程序控制自动赋值,此时就需要使用自动填充来实现该功能。<br />步骤1:修改数据库表,加入gmt_create、gmt_modifified字段,设置为datetime类型。
步骤2:修改实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
@TableName("t_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT) //新增时自动赋值
private Date gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE) //新增或修改时自动赋值
private Date gmtModifified;
}
步骤3:编写处理器处理 @TableField注解
@Slf4j
@Component //必须将当前处理器将由spring容器管理,否则不生效
public class MyMetaObjectHandler implements MetaObjectHandler {
//处理新增
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始insert填充......");
this.setFieldValByName("gmtCreate",new Date(),metaObject);
this.setFieldValByName("gmtModifified",new Date(),metaObject);
}
//处理修改
@Override
public void updateFill(MetaObject metaObject) {
log.info("开始update填充......");
this.setFieldValByName("gmtModifified",new Date(),metaObject);
}
}
乐观锁
乐观锁 : 对一切操作保持乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,
再次更新值测试 。 悲观锁:对一切操作保持悲观,它总是认为会出现问题,无论干什么都会上锁!再去操作! 乐观锁实现方式: 1.数据库表中应该有version字段,用于记录当前数据的版本 2.从数据库中取出记录时,获取当前 version 3.更新时,带上获得的version 4.执行更新时, set version = newVersion where version = oldVersion ,如果version不对,就更新失败。
-- 乐观锁:1、先查询,获得版本号 version = 1
-- A 线程开始执行操作
update user set name = "Jone", version = version + 1 where id = 2 and version = 1
-- B 线程抢先完成,这个时候 version = 2,会导致 A 线程修改由于version条件不匹配而更新失败!
update user set name = "Jone", version = version + 1 where id = 2 and version = 1
步骤1:修改数据库表,增加version字段,默认值为1
步骤2:修改实体类,添加version属性
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
@TableName("t_user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
@Version //乐观锁
private Integer version;
@TableField(fill = FieldFill.INSERT) //新增时自动赋值
private Date gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE) //新增或修改时自动赋值
private Date gmtModifified;
}
步骤3:注册组件
@Configuration
public class MybatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
步骤4:测试
// 测试乐观锁更新成功!
@Test
public void testOptimisticLocker(){
// 1、查询用户信息
User user = userMapper.selectById(1L);
// 2、修改用户信息
user.setName("jackson");
user.setEmail("jackson@163.com");
// 3、执行更新操作
userMapper.updateById(user);
}
// 测试乐观锁更新失败!多线程下
@Test
public void testOptimisticLocker2(){
// 线程 1
User user = userMapper.selectById(1L);
user.setName("Jone");
user.setEmail("Jone@163.com");
// 模拟另外一个线程执行了插队操作
User user2 = userMapper.selectById(1L);
user2.setName("joe");
user2.setEmail("joe@163.com");
userMapper.updateById(user2);
userMapper.updateById(user); // 如果没有乐观锁就会覆盖插队线程的值!
}
删除操作:delete
1.简单删除
@Test
public void testDeleteById(){
userMapper.deleteById(4L);
}
@Test
public void testDeleteBatchId(){
userMapper.deleteBatchIds(Arrays.asList(1L,2L,3L));
}
@Test
public void testDeleteMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","张三");
userMapper.deleteByMap(map);
}
2.逻辑删除
物理删除 :从数据库中直接移除 逻辑删除 :数据并没有从数据库中被移除,而是通过一个字段来标记该字符是否失效! deleted = 0 ——> deleted = 1 系统管理员可以查看所有被删除的记录,防止由于误操作导致的数据丢失,类似于windows回收站。
步骤1:修改数据库表,增加deleted字段,默认值为0
步骤2:修改实体类,增加deleted属性
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
@TableName("t_user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
@Version //乐观锁
private Integer version;
@TableLogic //逻辑删除
private Integer deleted;
@TableField(fill = FieldFill.INSERT) //新增时自动赋值
private Date gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE) //新增或修改时自动赋值
private Date gmtModifified;
}
步骤3:注册组件
@Configuration
public class MybatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
//注册逻辑删除组件
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
步骤4:修改配置文件
server:
port: 8888
servlet:
context-path: /mp
spring:
application:
name: mp
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/rbac?characterEncoding=UTF-8
username: root
password: root
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #配置mybatis-plus将日志打印到控制台
global-config:
db-config:
logic-delete-value: 1 #配置逻辑删除执行后的值
logic-not-delete-value: 0 #配置逻辑删除执行前的值
步骤5:测试删除操作
观察执行的SQL语句,此时执行的是update操作而不是delete,在数据库中,对应记录并没有被删除,只有deleted字段的值发生了改变。
查询操作:select
1.简单查询
@Test
public void testSelectById(){
User user = userMapper.selectById(5L);
System.out.println(user);
}
@Test
public void testSelectByBatchIds(){
userMapper.selectBatchIds(Arrays.asList(1L,2L,3L)).forEach(System.out::println);
}
@Test
public void testSelectByMap(){
Map<String, Object> map = new HashMap<>();
map.put("name","Jone");
userMapper.selectByMap(map).forEach(System.out::println);
}
2.分页查询
使用mybatis-plus提供的分页插件完成分页查询。<br />步骤1:注册组件
@Configuration
public class MybatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
// 逻辑删除组件
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
// 分页查询组件
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
步骤2:直接使用page对象完成分页操作
@Test
public void testPage(){
//参数1 : 当前页码
//参数2 : 每页记录数
Page<User> page = new Page<>(1,3);
//参数1 : 分页对象
//参数2 : 条件构造器
userMapper.selectPage(page,null);
//分页的信息都存放在page对象中,调用相应方法即可获取
page.getRecords().forEach(System.out::println);//获取查询到的记录
System.out.println(page.getTotal());//获取总记录数
System.out.println(page.getCurrent());//获取当前页码
System.out.println(page.getSize());//获取每页记录数
}
条件构造器
当应用中的某些业务需要使得复杂的sql操作时,可以使用条件构造器来完成相应需求。<br /> 官网: [https://baomidou.com/guide/wrapper.html](https://baomidou.com/guide/wrapper.html)
查询条件构造器(QueryWrapper)
@Test
public void testQueryWrapper(){
//泛型指定当前条件构建时使用的实体类对象
QueryWrapper<User> wrapper = new QueryWrapper<>();
//实现功能:查询姓名和email不为空且年龄大于等于20的所有记录
wrapper.isNotNull("name")
.isNotNull("email")
.ge("age",20);
userMapper.selectList(wrapper).forEach(System.out::println);
}
修改条件构造器(UpdateWrapper)
@Test
public void testUpDateWrapper1(){
User user = new User();
user.setName("张无忌");
user.setAge(88);
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("id",2L);
int update = userMapper.update(user,wrapper);
}
@Test
public void testUpDateWrapper2(){
User user = new User();
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.set("name","赵敏")
.set("age",88)
.eq("id",2L);
int update = userMapper.update(user,wrapper);
}
其他插件扩展
性能分析插件
作用:性能分析拦截器,用于输出每条 SQL 语句及其执行时间,主要用于测试慢sql。MP也提供性能分析插件,如果超过这个时间就停止运行!<br />步骤1:注册组件
@Configuration
public class MybatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
//注册逻辑删除组件
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
//注册分页组件
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
//注册性能分析组件
@Bean
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
//常用配置
//设置sql语句最大运行超时时间,超过则停止,时间单位为毫秒
performanceInterceptor.setMaxTime(1000);
//是否格式化代码
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
}
步骤2:修改配置文件(性能分析组件运行在dev或test环境下,生产环境不允许)
server:
port: 8888
servlet:
context-path: /mp
spring:
profiles:
active: dev # 配置运行环境
application:
name: mp
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/rbac?characterEncoding=UTF-8
username: root
password: root
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #配置mybatis-plus将日志打印到控制台
global-config:
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
步骤3:测试
将sql最大运行时间设置为10ms,随意执行某一条查询,此时会报异常:com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: The SQL execution time is too large, please optimize !<br /> 将sql最大运行时间设置为1000ms,再执行同一条查询语句,只要该sql执行时间没有超出1000ms,则会执行成功。
代码自动生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
步骤1:创建springboot项目
步骤2:引入相关依赖
<!-- mp自动代码生成时需要使用velocity -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<!-- mybatis-plus 是个人开发者发布的,并非官方发布! -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</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>
<!-- mp生成实体类时使用swagger2的注解,需要引入对应依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
步骤3:配置文件
server:
port: 8888
servlet:
context-path: /mp
spring:
profiles:
active: dev # 配置开发环境
application:
name: mp
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/rbac?characterEncoding=UTF-8
username: root
password: root
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #配置mybatis-plus将日志打印到控制台
global-config:
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
步骤4:创建自动生成代码的类
/**
* 代码自动生成器
*/
public class MybatisPlusAutoCode {
public static void main(String[] args) {
//构建代码自动生成器对象
AutoGenerator autoGenerator = new AutoGenerator();
//配置自动生成策略
// 1、全局配置:
//https://baomidou.com/config/generator-config.html#%E5%85%A8%E5%B1%80%E7%AD%96%E7%95%A5-globalconfig-%E9%85%8D%E7%BD%AE
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir"); //获取当前项目所在目录
gc.setOutputDir(projectPath+"/src/main/java"); //自定义代码生成后的存放目录
gc.setAuthor("hujianying"); //设置项目作者
gc.setOpen(false); //代码生成后是否打开文件夹
gc.setFileOverride(false); //是否覆盖
gc.setServiceName("%sService"); //去Service的I前缀
gc.setIdType(IdType.ID_WORKER); //自定义主键生成策略
gc.setDateType(DateType.ONLY_DATE); //自定义日期类型
gc.setSwagger2(true); //实体使用swagger2注解
autoGenerator.setGlobalConfig(gc); //添加全局配置
//2、设置数据源:
// https://baomidou.com/config/generator-config.html#%E6%95%B0%E6%8D%AE%E6%BA%90-datasourceconfig-%E9%85%8D%E7%BD%AE
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/rbac?characterEncoding=utf-8");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL); //指定数据库类型
autoGenerator.setDataSource(dsc); //添加数据源配置
//3、包名配置:
// https://baomidou.com/config/generator-config.html#%E5%8C%85%E5%90%8D%E9%85%8D%E7%BD%AE
PackageConfig pc = new PackageConfig();
pc.setModuleName("rbac"); //指定生成的模块名称
pc.setParent("com.woniu"); //设置模块中的父目录名
pc.setEntity("entity"); //设置实体类目录名
pc.setMapper("mapper"); //设置mapper目录名
pc.setService("service"); //设置service目录名
pc.setController("controller"); //设置controller目录名
autoGenerator.setPackageInfo(pc);
//4、数据库表配置:
// https://baomidou.com/config/generator-config.html#%E6%95%B0%E6%8D%AE%E5%BA%93%E8%A1%A8%E9%85%8D%E7%BD%AE
StrategyConfig strategy = new StrategyConfig();
// 设置要生成的实体类对应映射的表名
strategy.setInclude("t_perms","t_role","t_user");
strategy.setTablePrefix("t_"); //去除表名前缀
//设置表名生成策略,下划线转驼峰
strategy.setNaming(NamingStrategy.underline_to_camel);
//设置列名生成策略,下划线转驼峰
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true); //自动lombok;
strategy.setLogicDeleteFieldName("deleted"); //设置使用逻辑删除策略的属性名
// 自动填充配置 TableFill
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
strategy.setVersionFieldName("version"); // 乐观锁
strategy.setRestControllerStyle(true); //生成 @RestController 控制器
strategy.setControllerMappingHyphenStyle(true); //驼峰转连字符--->localhost:8080/hello_id_2
autoGenerator.setStrategy(strategy);
//执行自动生成
autoGenerator.execute();
}
}
步骤5:运行代码自动生成类,可在当前项目中生成对应的mapper、service、controller、xml等。