MyBatisPlus入门与实践指南
导航
- 学习内容:MyBatisPlus入门,注解,配置,条件构造器,自定义SQL,IService
1. MyBatisPlus入门
MyBatisPlus(MP)是MyBatis的增强工具,提供了更便捷的CRUD操作。以下是入门步骤:
引入依赖
首先,在项目中引入MyBatisPlus的依赖:
xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
如果项目中已经使用了MyBatis,可以移除原有的MyBatis依赖。
继承MP的Mapper接口
创建一个Mapper接口,继承BaseMapper
:
java
public interface UserMapper extends BaseMapper<User> {
}
这样就可以直接使用MP提供的CRUD方法,无需手动编写SQL语句。
示例代码
java
@Test
void testSelectById() {
User user = userMapper.queryUserById(5L);
System.out.println("user = " + user);
}
注意 :如果定义了与BaseMapper
方法同名的方法,BaseMapper
的方法将被优先使用。
2. 常用注解和配置
MyBatisPlus通过实体类的反射来映射数据库表信息,支持多种注解和配置。
实体类注解
-
指定表名 :
java@TableName("tb_user") public class User { }
-
指定主键及其策略 :
java@TableId(value = "id", type = IdType.AUTO) private Long id;
IdType.AUTO
:自增IDIdType.INPUT
:手动输入IdType.ASSIGN_ID
:雪花算法(随机),也是默认策略
-
指定字段名 :
java@TableField("username") private String username;
-
布尔值字段,
is
前缀会被自动去除:java@TableField("is_right") private Boolean isRight;
-
避免与数据库的关键字段冲突:
java@TableField("`other`") private Integer other;
-
全局配置
MyBatisPlus支持MyBatis的原生配置,并提供了全局策略配置:
yaml
mybatis-plus:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.itheima.mp.domain.po
configuration:
map-underscore-to-camel-case: true # 开启驼峰命名
cache-enabled: false # 禁用二级缓存
global-config:
db-config:
id-type: auto # 全局主键策略
update-strategy: not_null # 默认更新策略
3. 条件构造器和自定义SQL
MyBatisPlus提供了强大的条件构造器,用于动态构造SQL语句。
QueryWrapper
java
@Test
void testQueryWrapper() {
QueryWrapper<User> queryWrapper = new QueryWrapper<User>()
.select("id", "username", "phone", "info", "balance")
.like("username", "o")
.ge("balance", 1000);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
LambdaWrapper
通过反射获取字段名称,更加类型安全:
java
@Test
void testLambdaWrapper() {
LambdaQueryWrapper<User> queryWrapper = new QueryWrapper<User>()
.lambda()
.select(User::getId, User::getUsername, User::getPhone, User::getInfo, User::getBalance)
.like(User::getUsername, "o")
.ge(User::getBalance, 1000);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
自定义SQL
可以直接编写SQL语句:
java
@Test
void testUpdateWrapper() {
List<Long> ids = List.of(1L, 2L, 4L);
UpdateWrapper<User> updateWrapper = new UpdateWrapper<User>()
.setSql("balance = balance - 100")
.in("id", ids);
userMapper.update(null, updateWrapper);
}
条件比较函数
gt
:大于(>
)ge
:大于等于(>=
)lt
:小于(<
)le
:小于等于(<=
)eq
:等于(=
)ne
:不等于(!=
或<>
)
条件构造器与Mapper混合使用
java
@Test
void testCustomSql() {
List<Long> ids = List.of(1L, 2L, 4L);
int amount = 200;
LambdaQueryWrapper<User> queryWrapper = new QueryWrapper<User>()
.lambda()
.in(User::getId, ids);
userMapper.updateBalance(queryWrapper, amount);
}
注意 :构造器固定以"ew"
为参数值:
java
void updateBalance(@Param("ew") LambdaQueryWrapper<User> queryWrapper, int amount);
在Mapper XML中:
xml
<update id="updateBalance">
update user set balance = balance + #{amount}
${ew.customSqlSegment}
</update>
4. IService
通过IService
进一步简化操作。
继承IService
在接口中继承IService
:
java
public interface IUserService extends IService<User> {
}
实现类
实现类继承ServiceImpl
:
java
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}
使用IService方法
可以直接使用IService
的内置方法:
java
@ApiOperation("新增用户")
@PostMapping
public void saveUser(@RequestBody UserFormDTO userFormDTO) {
User user = BeanUtil.copyProperties(userFormDTO, User.class);
userService.save(user);
}
业务处理
在ServiceImpl
中,可以直接使用IService
和Mapper
层的方法:
java
public void deductBalance(Long id, Integer money) {
User user = this.getById(id);
baseMapper.deductBalance(id, money);
}
也可以使用Lambda构造业务逻辑:
java
@Override
@Transactional
public void deductBalance(Long id, Integer money) {
User user = this.getById(id);
if (user == null || user.getStatus() == 2) {
throw new RuntimeException("用户不存在或已冻结");
}
if (user.getBalance() < money) {
throw new RuntimeException("余额不足");
}
int balance = user.getBalance() - money;
lambdaUpdate()
.set(User::getBalance, balance)
.set(balance < 0, User::getStatus, 2)
.eq(User::getId, id)
.eq(User::getBalance, user.getBalance()) // 乐观锁
.update();
}
Lambda查询
java
@Override
public List<User> queryUsers(UserQuery userQuery) {
String name = userQuery.getName();
Integer status = userQuery.getStatus();
Integer minBalance = userQuery.getMinBalance();
Integer maxBalance = userQuery.getMaxBalance();
return lambdaQuery()
.like(name != null, User::getUsername, name)
.eq(status != null, User::getStatus, status)
.ge(minBalance != null, User::getBalance, minBalance)
.le(maxBalance != null, User::getBalance, maxBalance)
.list();
}
5. 批量操作
批量新增
采取分组发送的方式,避免通信传输和内存占用过大:
java
@Test
void testSaveBatch() {
List<User> list = new ArrayList<>(1000);
long b = System.currentTimeMillis();
for (int i = 1; i < 100000; i++) {
list.add(buildUser(i));
if (i % 1000 == 0) {
userService.saveBatch(list);
list.clear();
}
}
long e = System.currentTimeMillis();
System.out.println("耗时:" + (e - b));
}
注意 :尽管开启了批量保存,但MySQL默认会逐条插入。需要额外开启rewriteBatchedStatements=true
。
6. 小技巧
Lombok注解
使用Lombok的@RequiredArgsConstructor
注解可以自动生成构造器,简化依赖注入:
java
@RequiredArgsConstructor
public class UserController {
private final IUserService userService;
}