d41:MyBatisPlus入门,注解,配置,条件构造器,自定义SQL,IService

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:自增ID
    • IdType.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中,可以直接使用IServiceMapper层的方法:

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;
}
相关推荐
Li.CQ2 小时前
SQL学习笔记(二)
笔记·sql·学习
小二·4 小时前
MyBatis基础入门《十五》分布式事务实战:Seata + MyBatis 实现跨服务数据一致性
分布式·wpf·mybatis
小二·4 小时前
MyBatis基础入门《十四》多租户架构实战:基于 MyBatis 实现 SaaS 系统的动态数据隔离
数据库·架构·mybatis
白衣衬衫 两袖清风4 小时前
SQL联查案例
数据库·sql
晨曦5432107 小时前
MySQL MOD()函数详解与Python对比
sql
甘露s8 小时前
MySQL深入之索引、存储引擎和SQL优化
数据库·sql·mysql
偶遇急雨洗心尘8 小时前
记录一次服务器迁移时,数据库版本不一致导致sql函数报错和系统redirect重定向丢失域名问题
运维·服务器·数据库·sql
Logic1019 小时前
《Mysql数据库应用》 第2版 郭文明 实验5 存储过程与函数的构建与使用核心操作与思路解析
数据库·sql·mysql·学习笔记·计算机网络技术·形考作业·国家开放大学
小二·9 小时前
MyBatis基础入门《十六》企业级插件实战:基于 MyBatis Interceptor 实现 SQL 审计、慢查询监控与数据脱敏
数据库·sql·mybatis
小二·9 小时前
MyBatis基础入门《十二》批量操作优化:高效插入/更新万级数据,告别慢 SQL!
数据库·sql·mybatis