mybatis-plus
Mybatisplus特性:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
快速开始
引入依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.11</version>
</dependency>
注意:mybatis和mybatis-plus的依赖最好不要一起引入,不然可能造成重复依赖
在Spring Boot启动类中添加@MapperScan注解,扫描Mapper文件,路径为Mapper文件的路径
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
编写与数据库表对应的实体类
@Data
@TableName("`user`") //指定操作的表
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
编写Mapper层接口
public interface UserMapper extends BaseMapper<User> {
}
接下来便可以直接开始使用了!
如果Mybatis-plus提供的CRUD代码不能满足业务需求,还可以在Mapper层接口中自行添加新的功能,拓展性强。节约了写基础的CRUD代码的时间。
分布式系统的全局唯一id
mybatis-plus中,采用雪花算法生成全局唯一id。
雪花算法:snowflake是Twitter开源的分布式ID生成算法,结果是一个Long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个结点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一
此外,mybatis-plus也支持其他的id生成策略
public enum IdType{
AUTO(0), //数据库id自增
NONE(1), //未设置主键
INPUT(2),// 手动输入
ID_WORKER(3), //默认的雪花算法
UUID(4), // uuid
ID_WORKER_STR(5); //雪花算法的字符串表示法
}
只需要在实体类的字段上添加注释即可
public class User{
@TableId(type=IdType.AUTO)
private Long id;
private String name;
.....
}
自动填充字段
实际项目开发中,数据库表基本要带上create_time,update_time等基本字段,因为是每张表都有的字段,因此可以在代码层配置自动填充。
在实体类字段使用@TableField注释来标记哪些字段需要自动填充
public class User {
@TableField(fill = FieldFill.INSERT)
private String createTime;
@TableField(fill = FieldFill.UPDATE)
private String updateTime;
// 其他字段...
}
创建一个类来实现MetaObjectHandler接口,并重写insertFill和updateFill方法
@Slf4j
@Component // 交给Springboot管理 也可以是@Bean注释
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始插入填充...");
this.strictInsertFill(metaObject, "createUserId", Long.class, 123456L)
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("开始更新填充...");
this.strictInsertFill(metaObject, "updateUserId", Long.class, 123456L)
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
乐观锁
编写配置类
@Configuration
@MapperScan("按需修改")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
在实体类字段加上@Version注解
import com.baomidou.mybatisplus.annotation.Version;
public class YourEntity {
@Version
private Integer version;
// 其他字段...
}
查询操作
条件查询
mybatis-plus通过接收map类型的参数,实现条件查询,将需要筛选的条件放入map中
@Test
public void testSelect(){
HashMap<String,Object> map = new HashMap<>();
// 需要设置的条件
map.put("name","blueocean");
map.put("age",18);
List<User> users = userMapper.selectByMap(map);
}
分页查询
添加配置类即可
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
// 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
return interceptor;
}
}
使用时需要传入page对象作为参数
@Test
public void testPage(){
Page<User> page = new Page<>(1,5); // 第一个参数为当前页,第二个参数为分页大小
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
}
逻辑删除
逻辑删除是一种优雅的数据管理策略,它通过在数据库中标记记录为“已删除”而非物理删除,来保留数据的历史痕迹,同时确保查询结果的整洁性。一般为数据库表添加逻辑删除字段deleted
在application.yml中配置MyBatis-Plus的全局逻辑删除属性
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除字段名
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值
在实体类中为逻辑删除字段使用@TableLogic注解
import com.baomidou.mybatisplus.annotation.TableLogic;
public class User {
// 其他字段...
@TableLogic
private Integer deleted;
}
条件构造器
MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件,无需编写繁琐的 SQL 语句,从而提高开发效率并减少 SQL 注入的风险。
主要的Wapper类型:
-
AbstractWrapper:这是一个抽象基类,提供了所有 Wrapper 类共有的方法和属性。它定义了条件构造的基本逻辑,包括字段(column)、值(value)、操作符(condition)等。所有的 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper 都继承自 AbstractWrapper。
-
QueryWrapper:专门用于构造查询条件,支持基本的等于、不等于、大于、小于等各种常见操作。它允许你以链式调用的方式添加多个查询条件,并且可以组合使用 and 和 or 逻辑。
-
UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。与 QueryWrapper 类似,它也支持链式调用和逻辑组合。使用 UpdateWrapper 可以在不创建实体对象的情况下,直接设置更新字段和条件。
-
LambdaQueryWrapper:这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。
-
LambdaUpdateWrapper:类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。
Wrapper方法通常接受一个boolean类型的参数,用于决定是否将该条件加入到最终的SQL中,相当于动态sql的控制。
queryWrapper.like(StringUtils.isNotBlank(name), Entity::getName, name)
.eq(age != null && age >= 0, Entity::getAge, age);
常用方法:
- ne:设置单个字段不相等
// 设置指定字段的不相等条件
ne(R column, Object val)
// 根据条件设置指定字段的不相等条件
ne(boolean condition, R column, Object val)
- gt:用于设置单个字段大于条件
// 设置指定字段的大于条件
gt(R column, Object val)
// 根据条件设置指定字段的大于条件
gt(boolean condition, R column, Object val)
- ge:用于设置单个字段大于等于条件
- lt
- le
- between:用于设置单个字段的BETWEEN条件
// 设置指定字段的 BETWEEN 条件
between(R column, Object val1, Object val2)
// 根据条件设置指定字段的 BETWEEN 条件
between(boolean condition, R column, Object val1, Object val2)
- like:模糊查询
// 设置指定字段的 LIKE 条件
like(R column, Object val)
// 根据条件设置指定字段的 LIKE 条件
like(boolean condition, R column, Object val)
- inSql:MyBatis-Plus 中用于构建查询条件的高级方法之一,它用于设置单个字段的 IN 条件,并且允许直接使用sql语句生成IN子句中的集合(子查询)
// 设置指定字段的 IN 条件,使用 SQL 语句
inSql(R column, String sqlValue)
inSql(boolean condition, R column, String sqlValue)
// 普通
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("age", "1,2,3,4,5,6");
// 子查询
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("id", "select id from other_table where id < 3");
上述子查询生成的SQL
SELECT * FROM user WHERE id IN (select id from other_table where id < 3)
代码生成器
可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
依赖注入
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.11</version>
</dependency>
快速使用
public static void main(String[] args) {
FastAutoGenerator.create("url", "username", "password")
.globalConfig(builder -> {
builder.author("baomidou") // 设置作者
.enableSwagger() // 开启 swagger 模式
.outputDir(Paths.get(System.getProperty("user.dir")) + "/src/main/java"); // 指定输出目录
})
.dataSourceConfig(builder ->
builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
int typeCode = metaInfo.getJdbcType().TYPE_CODE;
if (typeCode == Types.SMALLINT) {
// 自定义类型转换
return DbColumnType.INTEGER;
}
return typeRegistry.getColumnType(metaInfo);
})
)
.packageConfig(builder ->
builder.parent("com.baomidou.mybatisplus") // 设置父包名
.moduleName("system") // 设置父包模块名
.entity("entity")
.mapper("mapper")
.service("service")
.serviceImpl("service.impl")
.xml("mapper.xml")
)
.strategyConfig(builder ->
builder.addInclude("t_simple") // 设置需要生成的表名
.addTablePrefix("t_", "c_") // 设置过滤表前缀
.enableLombok() // 使用lombok
)
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}