提高后端接口性能的方法

发布于:2024-11-03 ⋅ 阅读:(62) ⋅ 点赞:(0)

个人bibilailai(不喜请跳过):前几天参加的部门技术分享会,同事分享了一个内容为“提高接口性能的常见技巧”,个人觉得很有用,所以想在这里分享给大家,希望对刚入职场不久的兄弟姐妹们有所帮助。

1.避免大事物

大事务:有事务的方法的运行时间比较长,长时间未提交的事务。

1.1 大事务产生的原因

  • 操作的数据比较多
  • 大量的锁竞争
  • 事务中有其他非DB的耗时操作

1.2 大事务造成的影响

  • 并发情况下,数据库连接池容易被撑爆
  • 锁定太多的数据,造成大量的阻塞和锁超时,甚至导致死锁
  • 执行时间长,容易造成主从延迟
  • 回滚所需要的时间比较长
  • undo log膨胀

1.3 例子

反例:

@Transactional(rollbackFor=Exception.class)
   public void save(Req req) {
         checkParam(req);
         saveData1(req);
         updateData2(req);
   }

   private void checkParam(Req req){
       Data1 data = selectData1();
       Data2 data2 = selectData2();
       if(data.getSomeThing() != STATUS_YES){
          throw new BusinessTimeException(.....);
       }
   }

优化思路:一般只需要把与数据库的插入和修改操作放在事务里面,其他的校验以及查询数据等等都不需要放在事务内。

正例:

class ServiceAImpl implements ServiceA {
  @Transactional(rollbackFor=Exception.class)
   public void save(Req req) {
         saveData1(req);
         updateData2(req);
   }

   private void checkParam(Req req){
       Data1 data = selectData1();
       Data2 data2 = selectData2();
       if(data.getSomeThing() != STATUS_YES){
          throw new BusinessTimeException(.....);
       }
   }

 public void save(Req req){
    checkParam(req);
    doSave(req);
 }
}

2.异步调用

同步调用:也就是在你写的代码里面,在方法内部,必须按照从上往下的顺序执行,如果中间某一步报错了,就不能继续往下面执行了,全程只有一个主线程在执行。

异步调用:会在异步调用处启动另外一个线程1来执行被一步标记的那一步,全程有两个线程,除了线程1还有一个主线程,这两个线程是完全分开的,即使线程1报错也不会影响主线程的执行。

一般情况要看具体业务的时效性以及具体功能的必要性,比如注册会员,一般情况下会先修改用户数据,然后给用户发放100的奖励积分,其中对于发放积分这个操作就可以异步执行。

实现异步调用的方式有很多,这里就不赘述了。

3.添加索引

为表添加适当的索引,大家可以参考我这篇文章:写文章-CSDN创作中心icon-default.png?t=O83Ahttps://mp.csdn.net/mp_blog/creation/editor/140501342

4.避免循环查数据库

开发是要尽量减少与数据库的交互,因为和数据库交互非常耗时,影响性能。

如下反例:

 @Override
    public List<Account> getAccountList(List<String> ids) {
        List<Account>  accounts = new ArrayList<>();
        for (String id : ids) {
            Account account = mapper.selectById(id);
            accounts.add(account);
            //其他业务操作
        }
        return accounts;
    }

正例:直接一次性查出需要的所有数据:

  @Override
    public List<Account> getAccountList(List<String> ids) {
        List<Account> accounts = mapper.selectBatchIds(ids);
        return accounts;
    }

5.避免无限递归

特别是在不确定递归深度的时候,最好不要递归循环查数据库。

和上述避免循环查数据库是一样的道理。

方法有如下:

1.设定递归深度(也就是确定递归的次数)。

2.先查出所有的数据,然后去数据列表中筛选。