02MyBatisPlus条件构造器,自定义SQL,Service接口

一、条件构造器

1.MyBatis 支持各种复杂的where条件,满足开发的需求

Wrapper是条件构造器,构建复杂的where查询

AbstractWrapper有构造where条件的所有方法,QueryWrapper继承后并有自己的select指定查询字段。UpdateWrapper有指定更新的字段的方法

2. 案例:基于QueryWrapper查询

①查询出名字带"o"的,存款大于等于1000元的人的id,username,info,balance字段

java 复制代码
@Test
void test(){
    // 构建查询条件
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
            .select("id","username","info","balance")
            .like("username","o") // where条件
            .ge("balance",1000);
    // 查询
    user2Mapper.selectList(wrapper);
}

LambdaQueryWrapper 方法

java 复制代码
@Test
void testl() {
   // 构建查询条件
   LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
         .select(User::getId, User::getUsername, User::getInfo, User::getBalance)
         .like(User::getUsername, "o") // where条件
         .ge(User::getBalance, 1000);
   // 查询
   List<User> users = user2Mapper.selectList(wrapper);
   System.out.println(users);
}

②更新用户名为jack的用户的余额为2000

java 复制代码
@Test
void test2(){
    // 更新字段
    User user = new User();
    user.setBalance(2000);
    // 构建查询条件
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
            .eq("username","jack");
    user2Mapper.update(user, wrapper);
}

update(更新的数据,更新的条件)

3. 案例:基于UpdateWrapper更新

①更新id为1,2,4的用户的金额扣200

java 复制代码
@Test
void test3() {
   // 更新条件的ids
   List<Long> ids = new ArrayList<>();
   ids.add(1L);
   ids.add(2L);
   ids.add(4L);
   // 更新的内容和条件
   UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
         .setSql("balance = balance - 200")
         .in("id",ids);
   user2Mapper.update(null, wrapper);
}

4. 条件构造器的用法总结

①QueryWrapper和LambdaQueryWrapper通常构建select,delete,update的wher条件部分

②UpdateWrapper和LambdaUpdateWrapper通常只有在set语句比较特殊才使用

③尽量使用LambdaQueryWrapper和LambdaUpdateWrapper,避免硬编码。

二、自定义SQL

1. 用法

通过MP的Wrapper来构建复杂的where条件,然后自己定义SQL语句剩下的部分。

2. 案例将id在指定范围内的用户(1,2,4)的余额扣减指定值

把mp构建好的条件传递到mapper,进行sql组装

①基于Wrapper构建where条件

java 复制代码
@Test
void test3() {
   // 更新条件的ids
   List<Long> ids = new ArrayList<>();
   ids.add(1L);
   ids.add(2L);
   ids.add(4L);
   // 更新的内容
   int amount = 200;
   // 编写where更新条件
   LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
         .in(User::getId,ids);
   // 用户自定义SQL
   user2Mapper.updateBalanceByIds(wrapper,amount);
}

②用户自定义mapper方法参数中用Param注解声明wrapper变量,必须是ew

java 复制代码
void updateBalanceByIds(@Param("ew") LambdaQueryWrapper<User> wrapper, @Param("amount")int amount);

③编写sql语句,进行where拼接

XML 复制代码
<update id="updateBalanceByIds">
    update tb_user set balance = balance - #{amount} ${ew.customSqlSegment}
</update>

三、Service接口

1.IService 接口的方法

2.IService 接口的继承

①自定义Service接口继承IService接口

②自定义Service实现类,实现自定义接口并继承ServiceImpl类

③新增用户案例

java 复制代码
@PostMapping
@ApiOperation("新增")
public void addUser(@RequestBody UserFormDTO userFormDTO){
   // DTO拷贝到PO
   User user = new User();
   BeanUtils.copyProperties(userFormDTO,user);
   // 保存
   userService.save(user);
}

3. 案例:IService的Lambda查询

需求:实现一个根据复杂条件查询用户的接口,查询条件如下:

name:用户名关键字,可以为空

status:用户状态,可以为空

原始的MyBatis

LambdaQuery

java 复制代码
@Override
public List<User> getUserList(UserQuery query) {
   // 获取参数
   String name = query.getName();
   Integer status = query.getStatus();
   // 构造查询语句
   return lambdaQuery()
         .like(name != null, User::getUsername, name)
         .eq(status != null, User::getStatus, status)
         .list();
}

4. 案例:IService的Lambda更新

需求:改造根据id修改用户余额的接口,要求如下

完成对用户状态校验

完成对用户余额校验

如果扣减后余额为0,则将用户status修改为冻结状态2

java 复制代码
@Service
public class UserServiceImpl extends ServiceImpl<User2Mapper, User> implements IUserService {
   @Override
   public void deductBalance(String id, Integer money) {
      // 查询用户
      User user = getById(id);
      // 检验用户状态
      if (user == null || user.getStatus() == 2) {
         throw new RuntimeException("用户状态异常");
      }
      // 检验余额
      if (user.getBalance() < money) {
         throw new RuntimeException("余额不足");
      }
      // 扣减余额
      int remainBalance = user.getBalance() - money;
      // 执行更新
      lambdaUpdate()
            .set(User::getBalance,remainBalance)
            .set(remainBalance==0,User::getStatus,2)
            .eq(User::getId,id)
            .update();
   }

5.IService 的批量新增

需求:批量插入10万条用户数据,并作出对比:

  • 普通for循环插入
  • IService的批量插入

①构建批量插入的方法

java 复制代码
// 批量插入的方法
private User buildUser(int i){
   User user = new User();
   user.setUsername("Wang_"+i);
   user.setPassword("123");
   user.setPhone("18688990011"+i+"");
   user.setBalance(200);
   user.setInfo("{\"age\": 26, \"intro\": \"英文老师\", \"gender\": \"female\"}");
   user.setCreateTime(LocalDateTime.now());
   user.setUpdateTime(LocalDateTime.now());
   return user;
}

②使用普通的for循环插入

java 复制代码
@Test
void testSaveOneByOne() {
   long b = System.currentTimeMillis();
   // 循环插入
   for (int i = 1; i < 100000; i++) {
      userService.save(buildUser(i));
   }
   long e = System.currentTimeMillis();
   System.out.println("耗时" + (e - b));
}

耗时:210005ms,210s

②使用批处理

java 复制代码
@Test
void testSaveBatch(){
   // 每次批量插入1000,插入100次就是10万条数据
   // 1.准备1个容量为1000的集合
   List<User> list = new ArrayList<>(1000);
   long b = System.currentTimeMillis();
   for (int i = 0; i < 100000; i++) {
      // 2.添加一个user
      list.add(buildUser(i));
      // 3.每1000条批量插入一次
      if (i % 1000 == 0){
         // 4. 批量插入
         userService.saveBatch(list);
         // 5. 清空
         list.clear();
      }
   }
   long e = System.currentTimeMillis();
   System.out.println("耗时" + (e - b));
}

耗时:26258ms,26s

性能进一步提升,配置jdbc参数,开rewriteBatchedStatements=true

总结:

  • 普通for循环逐条插入速度极差,不推荐
  • MP的批量新增,基于预编译的批处理,性能不错
  • 配置jdbc参数,开rewriteBatchedStatements=true,性能最好
相关推荐
Karoku06638 分钟前
【企业级分布式系统】ELK优化
运维·服务器·数据库·elk·elasticsearch
莫叫石榴姐1 小时前
数据科学与SQL:组距分组分析 | 区间分布问题
大数据·人工智能·sql·深度学习·算法·机器学习·数据挖掘
小技与小术2 小时前
数据库表设计范式
数据库·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作
运维·服务器·数据库·sql·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验九 触发器
数据库·sql·mysql·oracle·实验报告
Loganer2 小时前
MongoDB分片集群搭建
数据库·mongodb
LKID体2 小时前
Python操作neo4j库py2neo使用之创建和查询(二)
数据库·python·neo4j
刘大浪2 小时前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
一只爱撸猫的程序猿2 小时前
简单实现一个系统升级过程中的数据平滑迁移的场景实例
数据库·spring boot·程序员
无敌岩雀3 小时前
MySQL中的索引
数据库·mysql