个人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创作中心https://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.先查出所有的数据,然后去数据列表中筛选。