概述
MyBatis-Plus 是 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,简化开发、提高效率。本文将介绍 MyBatis-Plus 的几个核心功能在实际项目中的应用
条件构造器
MyBatis-Plus 提供了强大的条件构造器 Wrapper,可以方便地构建复杂的查询条件。如下:
基本查询
java
// 查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("username", "a")
.between("age", 20, 30)
.isNotNull("email");
List<User> list = userMapper.selectList(queryWrapper);
排序查询
java
// 按年龄降序查询用户,如果年龄相同则按id升序排列
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age").orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
Lambda 表达式
使用 Lambda 表达式可以避免字段名的硬编码,提高代码的可读性和安全性
java
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
.like(StringUtils.isNotBlank(username), User::getName, username)
.ge(ageBegin != null, User::getAge, ageBegin)
.le(ageEnd != null, User::getAge, ageEnd);
@TableName 注解
@TableName 注解用于指定实体类对应的数据库表名。如下:
java
@Data
@TableName("product")
public class Product {
private Long id;
private String name;
private Integer price;
@Version
private Integer version;
}
如果没有使用 @TableName 注解,MyBatis-Plus 会默认使用类名小写形式作为表名
Condition 条件判断
MyBatis-Plus 的条件构造器支持条件判断,可以根据参数是否为 null 来决定是否添加该条件
java
@Test
public void test08() {
String username = null;
Integer ageBegin = 10;
Integer ageEnd = 24;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if(StringUtils.isNotBlank(username)){
queryWrapper.like("username","a");
}
if(ageBegin != null){
queryWrapper.ge("age", ageBegin);
}
if(ageEnd != null){
queryWrapper.le("age", ageEnd);
}
List<User> users = userMapper.selectList(queryWrapper);
}
更简洁的写法是使用 Lambda 表达式:
java
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
.like(StringUtils.isNotBlank(username), User::getName, username)
.ge(ageBegin != null, User::getAge, ageBegin)
.le(ageEnd != null, User::getAge, ageEnd);
乐观锁实现
乐观锁是解决并发问题的一种有效方式。MyBatis-Plus 通过 @Version 注解实现乐观锁功能
配置乐观锁插件
在 config 包下配置乐观锁插件:
java
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
实体类添加版本号字段
在实体类中添加版本号字段(@Version):
java
@Data
public class Product {
private Long id;
private String name;
private Integer price;
@Version
private Integer version;
}
乐观锁测试
java
@Test
public void testConcurrentVersionUpdate() {
// 小李取数据
Product p1 = productMapper.selectById(1L);
// 小王取数据
Product p2 = productMapper.selectById(1L);
// 小李修改 + 50
p1.setPrice(p1.getPrice() + 50);
int result1 = productMapper.updateById(p1);
// 小王修改 - 30
p2.setPrice(p2.getPrice() - 30);
int result2 = productMapper.updateById(p2);
if (result2 == 0) {
// 失败重试,重新获取version并更新
p2 = productMapper.selectById(1L);
p2.setPrice(p2.getPrice() - 30);
result2 = productMapper.updateById(p2);
}
}
代码生成器
MyBatis-Plus 提供了代码生成器,可以快速生成 Entity、Mapper、Service、Controller 等代码:
java
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false", "root", "123456")
.globalConfig(builder -> {
builder.author("qcby")
.fileOverride()
.outputDir("D://mybatis_plus");
})
.packageConfig(builder -> {
builder.parent("com.qcby")
.moduleName("mybatisplus")
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus"));
})
.strategyConfig(builder -> {
builder.addInclude("t_user")
.addTablePrefix("t_", "c_");
})
.templateEngine(new FreemarkerTemplateEngine())
.execute();
多数据源配置
MyBatis-Plus 结合 dynamic-datasource 可以轻松实现多数据源配置
数据源配置
在 application.yml 中配置多个数据源
XML
spring:
datasource:
dynamic:
primary: master
strict: false
datasource:
master:
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
username: root
password: 123456
slave_1:
url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
username: root
password: 123456
服务层指定数据源
在服务实现类上使用 @DS 注解指定数据源
java
@DS("master")
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
@DS("slave_1")
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
}
多数据源测试
java
@Test
public void testDynamicDataSource(){
System.out.println(userService.getById(1L)); // 使用master数据源
System.out.println(productService.getById(1L)); // 使用slave_1数据源
}