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;
}
相关推荐
少废话h16 小时前
Spark 中数据读取方式详解:SparkSQL(DataFrame)与 SparkCore(RDD)方法对比及实践
大数据·sql·spark
codingPower17 小时前
升级mybatis-plus导致项目启动报错: net.sf.jsqlparser.statement.select.SelectBody
java·spring boot·maven·mybatis
jiuweiC18 小时前
常用es sql
大数据·sql·elasticsearch
珊珊而川1 天前
MAC-SQL 算法一
数据库·sql·oracle
听风吟丶1 天前
深入解析 Spring Boot 自动配置:原理、实践与进阶
java·数据库·sql
风语者日志1 天前
[LitCTF 2023]这是什么?SQL !注一下 !
android·数据库·sql
呆呆小金人1 天前
SQL视图:虚拟表的完整指南
大数据·数据库·数据仓库·sql·数据库开发·etl·etl工程师
啊吧怪不啊吧1 天前
SQL之表的查改(下)
大数据·数据库·sql
洛克大航海1 天前
解锁 PySpark SQL 的强大功能:有关 App Store 数据的端到端教程
linux·数据库·sql·pyspark sql
IT 小阿姨(数据库)1 天前
PostgreSQL pg_stat_bgwriter 视图各个字段详解
linux·数据库·sql·postgresql·centos