上一篇为mybatis-plus一些简单使用,现在我们来系统的学习一下mybatis-plus
Mybatis-plus简介
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
这一段简介是官网上写的,mybatis-plus不是用来替代mybatis的一个框架,而是用来增强mybatis的一个工具。Mybatis-plus是在MyBatis的基础上只做增强不做改变,是为了简化开发、提高效率而生的。
快速搭建
有一个简单数据库
1 2 3 4 5 6 7 8 9
| DROP TABLE IF EXISTS user; 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) );
|
添加一些测试数据
1 2 3 4 5 6 7
| DELETE FROM user; 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');
|
创建一个SpringBoot项目
引入依赖(当然还有一些Spring基础的依赖没有写上,大可不必这么完美)
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
|
创建我们的实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.bestrookie.pojo; import com.baomidou.mybatisplus.annotation.TableName; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @AllArgsConstructor @NoArgsConstructor
@TableName(value = "user") public class UserPojo { private Long id; private String name; private int age; private String email; }
|
创建mapper
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.bestrookie.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.bestrookie.pojo.UserPojo; import org.apache.ibatis.annotations.Mapper;
@Mapper public interface UserMapper extends BaseMapper<UserPojo> { }
|
从这里就体现出简化了mybatis,我们不需要去写额外的xml,mybatis自动帮我们完成简单的CRUD的实现。到这里我们就可以使用mapper进行一些简单的增删查改了。 可以自行进行一些简单的增删查改
MyBatis-Plus insert填充id
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void testInsert(){ UserPojo user = new UserPojo(); user.setAge(18); user.setEmail("123@123.com"); user.setName("rookie"); System.out.println("============================"); System.out.println(user); int insert = userMapper.insert(user); System.out.println(insert); System.out.println(user); }
|
这是我的测试代码,在运行的时候发现,我的测试数据并没有设置id的值,在我看来一般回出现两种结果
- 数据库设置自增id 会根据以前的数据自动增加
- 数据库没有设置自增 结果是null。
但是mybatis-plus 都不是上面情况:空的id 自动生成一串数字填充,插入到数据库中之后,回填到原来的数据当中
查阅资料之后知道 mybatis-plus根据雪花算法生成一个唯一主键进行填充。
设置主键自增
我们需要配置主键自增
1、实体类字段添加注解 @TableId(type = IdType.AUTO)
2、数据库字段一定是自增的
IdType源码解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public enum IdType { AUTO(0), NONE(1), INPUT(2), ID_WORKER(3), UUID(4), ID_WORKER_STR(5);
private int key;
private IdType(int key) { this.key = key; }
public int getKey() { return this.key; }
|
自动填充
在开发当中,在数据库中的字段要带有创建时间、修改时间,这些操作通常都是自动完成的,不应该是开发人员手动添加的。
在阿里巴巴手册中:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上,而且需要自动化。
方式一:数据库级别工作(工作中不循序修改数据库)
1、在数据库表中增加create_time,update_time
然后设置create_time和update_time的默认值为CURRENT_TIMESTAMP,update_time勾选
方式二:代码级别
1、删除数据库的默认值、更新操作
2、实体类字段属性上需要增加注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Data @AllArgsConstructor @NoArgsConstructor
@TableName(value = "user") public class UserPojo { @TableId(type = IdType.AUTO) private Long id; private String name; private int age; private String email; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; }
|
3、添加一个处理器,来处理这个注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.bestrookie.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;
@Component @Slf4j public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill...."); this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override public void updateFill(MetaObject metaObject) { log.info("start update fill...."); this.setFieldValByName("updateTime",new Date(),metaObject);
} }
|
乐观锁
乐观锁的实现方式:
- 取出记录,获取当前version
- 更新时,带上这个version
- 执行更新的时,
set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
使用乐观锁
首先在对应实体类的version字段上添加@Version注解
1 2 3 4 5 6 7 8 9 10 11 12
| public class UserPojo { @TableId(type = IdType.AUTO) private Long id; private String name; private int age; private String email; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; @Version private Integer version;
|
然后添加配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Configuration @MapperScan("按需修改") public class MybatisPlusConfig {
@Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); }
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } }
|
现在项目中就完后了设置乐观锁,所执行的每次修改操作,都会与比较version。
查询语句
1 2 3 4 5 6 7 8
| UserPojo user = userMapper.selectById(2);
List<UserPojo> userPojos = userMapper.selectBatchIds(Arrays.asList(1, 2, 3)); HashMap<String, Object> map = new HashMap<>(); map.put("name","jack");
userMapper.selectByMap(map);
|
分页查询
首先添加分解插件的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Configuration @MapperScan("com.bestrookie.mapper") public class MybatisPlusConfig { @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } @Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); }
}
|
直接使用Page对象进行分页
1 2 3 4 5
| @Test public void testPage(){ Page<UserPojo> page = new Page<>(1,5); IPage<UserPojo> userPojoIPage = userMapper.selectPage(page, null); }
|
删除操作
基本的删除操作
直接查看源码
1
| int deleteById(Serializable var1);
|
1
| int deleteBatchIds(@Param("coll") Collection<? extends Serializable> var1);
|
1
| int deleteByMap(@Param("cm") Map<String, Object> var1);
|
逻辑删除
首先在我们数据库表中添加一个deleted字段
在相应的实体类中添加属性并加上注解@TableLogic
1 2
| @TableLogic private Integer deleted;
|
在配置类中添加相应的配置
1 2 3 4 5
| @Bean public ISqlInjector sqlInjector(){ return new LogicSqlInjector(); }
|
在配置文件中添加配置
然后进行删除的测试
1 2 3 4
| @Test public void testDelete(){ userMapper.deleteById(1L); }
|
可以先执行的是更新的操作,而不是删除。
性能分析插件
输出每条SQL语句及其执行时间
首先在配置类里面配置性能分析插件
1 2 3 4 5 6 7 8
| @Bean @Profile({"dev","test"}) public PerformanceInterceptor performanceInterceptor(){ PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); performanceInterceptor.setMaxTime(1000); performanceInterceptor.setFormat(true); return performanceInterceptor; }
|
记住,要在SpringBoot中配置环境为dev或者test环境
随便运行一个方法进行测试
条件构造器
就是之前Wrapper 复杂的sql都靠这个
当我们需要写一些复杂的sql的时候,就需要自己创建相应的Wrapper进行定制,这个涉及方面比较多,建议根据官方文档进行学习,下面我们值进行一些用到最多的,进行测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| @SpringBootTest public class WrapperTest { @Autowired private UserMapper userMapper; @Test void contextLoads() { QueryWrapper<UserPojo> wrapper = new QueryWrapper<>(); wrapper.isNotNull("name").isNotNull("email").ge("age",12); userMapper.selectList(wrapper); } @Test void test2(){ QueryWrapper<UserPojo> wrapper = new QueryWrapper<>(); wrapper.eq("name","张全蛋"); userMapper.selectOne(wrapper); } @Test void test3(){ QueryWrapper<UserPojo> wrapper = new QueryWrapper<>(); wrapper.between("age",20,30); System.out.println(userMapper.selectCount(wrapper)); } @Test void test4(){ QueryWrapper<UserPojo> wrapper = new QueryWrapper<>(); wrapper.notLike("name","e"); List<Map<String, Object>> maps = userMapper.selectMaps(wrapper); System.out.println(maps.toString()); } @Test void test5(){ QueryWrapper<UserPojo> wrapper = new QueryWrapper<>(); wrapper.inSql("id","select id from user where id<3"); userMapper.selectObjs(wrapper); } @Test void test6(){ QueryWrapper<UserPojo> wrapper = new QueryWrapper<>(); wrapper.orderByDesc("id"); userMapper.selectList(wrapper); } }
|
代码生成器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| package com.bestrookie;
import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.config.DataSourceConfig; import com.baomidou.mybatisplus.generator.config.GlobalConfig; import com.baomidou.mybatisplus.generator.config.PackageConfig; import com.baomidou.mybatisplus.generator.config.StrategyConfig; import com.baomidou.mybatisplus.generator.config.po.TableFill; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
public class Code { public static void main(String[] args) { AutoGenerator mpg = new AutoGenerator();
GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir"); gc.setOutputDir(projectPath + "/src/main/java"); gc.setAuthor("ChanV"); gc.setOpen(false); gc.setFileOverride(false); gc.setServiceName("%sService"); gc.setIdType(IdType.ID_WORKER); gc.setDateType(DateType.ONLY_DATE); gc.setSwagger2(true); mpg.setGlobalConfig(gc);
DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/mybatis-plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); dsc.setDbType(DbType.MYSQL); mpg.setDataSource(dsc);
PackageConfig pc = new PackageConfig(); pc.setModuleName("blog"); pc.setParent("com.bestrookie"); pc.setEntity("pojo"); pc.setMapper("mapper"); pc.setService("service"); pc.setController("controller"); mpg.setPackageInfo(pc);
StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("user"); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true); strategy.setLogicDeleteFieldName("deleted"); TableFill createTime = new TableFill("create_time", FieldFill.INSERT); TableFill updateTime = new TableFill("update_time", FieldFill.UPDATE); ArrayList<TableFill> tableFills = new ArrayList<>(); tableFills.add(createTime); tableFills.add(updateTime); strategy.setTableFillList(tableFills); strategy.setVersionFieldName("version"); strategy.setRestControllerStyle(true); strategy.setControllerMappingHyphenStyle(true); mpg.setStrategy(strategy);
mpg.execute(); } }
|
点击获取代码