前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >提高API加载速度的4种方法,并应用于Java Spring Boot

提高API加载速度的4种方法,并应用于Java Spring Boot

原创
作者头像
zayyo
发布2023-12-24 16:48:01
2100
发布2023-12-24 16:48:01
举报
文章被收录于专栏:zayyo前端
  1. 分页

对于返回数组的 API 响应以及在表格、列表、选项等中使用大量数据,查询语句必须使用分页,不得获取全部数据。

Java Spring Boot

使用 JPA 和 Hibernate

代码语言:java
复制
List<Post> posts = entityManager.createQuery(
    "select p " +
    "from Post p " +
    "left join fetch p.comments " +
    "order by p.createdOn", Post.class)
.setFirstResult(10)
.setMaxResults(10)
.getResultList();

然而对于 Java Spring Boot,如果你有数千条记录并且使用了 join fetch,使用上述方式会出现如下警告:

HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!

特别需要注意 Hibernate N+1 问题

:( 从一开始为什么不直接说呢!直到性能问题出现才提到

为什么会有 HHH000104 警告,以及它对查询速度和响应有何影响,答案肯定是有的。

实际上 Hibernate 会将其编译成本地 SQL 查询,如下所示:

代码语言:java
复制
SELECT p.id AS id1_0\_0_
  
c.id AS id1_1_1_,
  p.created_on AS created_2_0_0_,
   p.title AS title3_0_0_,

   c.post_id AS post_id4_1_1_,
   c.review AS review3_1_1_,
   c.post_id AS post_id4_1_0__,
   c.id AS id1_1_0__

FROM post p

LEFT OUTER JOIN post\_comment c ON p.id=c.post\_id

ORDER BY p.created\_on

查询中没有任何与 limit、offset 或 row_number 相关的关键字,...

Hibernate 查询会获取所有数据,然后再进行实体/模型/DTO的反序列化,导致查询数据库时间很长

有两种解决这个问题的方法:

  • 方法1:使用两个查询语句

仅选择 post.id 以获取满足条件的 id 列表。

代码语言:java
复制
List<Long> postIds = entityManager.createQuery("""
    select p.id
    from Post p
    where p.title like :titlePattern
    order by p.createdOn
    """, Long.class)
.setParameter(
    "titlePattern",
    "High-Performance Java Persistence %"
)
.setMaxResults(5)
.getResultList();

获取到 post id 列表后,再查询包含在该列表中的 post。

代码语言:java
复制
List<Post> posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.comments
    where p.id in (:postIds)
    order by p.createdOn
    """, Post.class)
.setParameter("postIds", postIds)
.setHint(
    QueryHints.HINT_PASS_DISTINCT_THROUGH,
    false
)
.getResultList();

这种方式需要注意一下 postIds 数组的限制,因为它是有限制的。

  • 方法2:如果使用 Oracle Database,可以使用 DENSE_RANK 我还没有应用过这种方法,所以想要应用并了解更多细节,请参考此处。

除了 N+1 和分页,对于 Java Spring Boot Hibernate JPA,还有很多与性能相关的问题,比如 spring.jpa.open-in-view、Hikari:Connection is not available、request timeout after 30000ms、EntityGraph 等。如果你有兴趣,可以评论讨论哦 :D

  1. 异步日志记录

后端记录日志以监视错误、信息、调试是理所当然的,但如果日志不是异步记录,也会影响性能,这个问题在考虑性能时经常被忽略。

对于大型系统来说,请求量很大,如果日志不是异步记录,而是花费时间或者空间来解决逻辑和返回响应,则会降低 API 的延迟。

Java Spring Boot

如果使用 logback.xml,可以进行类似如下的配置:

代码语言:xml
复制
<configuration>
  <property name="LOG_PATTERN"
    value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" />

  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>
        ${LOG_PATTERN}
      </pattern>
    </encoder>
  </appender>

  <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>
      ./logs/application.log
    </file>
    <encoder>
      <pattern>
        ${LOG_PATTERN}
      </pattern>
    </encoder>

    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
      <fileNamePattern>
        ./logs/archive/application-%d{yyyy-MM-dd}-%i.log.zip
      </fileNamePattern>
      <maxFileSize>10MB</maxFileSize>
      <maxHistory>100</maxHistory>
    </rollingPolicy>
  </appender>

  <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="ROLLING_FILE" />
  </appender>

  <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="CONSOLE" />
  </appender>

  <root level="INFO">
    <appender-ref ref="ROLLING_FILE" />
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>
  1. 缓存

这项技术极大地提升了加载速度,并且有多种应用方式,比如 Redis,或者如果使用 Java Spring Boot,该框架也已经提供了

支持。

基本的缓存机制是根据键将数据存储在内存中,并且有一个过期时间。

通常第一次调用时不会很快,因为缓存还不存在,所以会直接查询数据库,之后的调用才会变快。

因此,我经常编写调度程序/定时任务/定时器,每天清晨系统将会预先获取和缓存用于大量数据查询的 API,比如列表、图表、统计等。

  1. 负载压缩

简而言之,这将在客户端的反序列化和响应时优化数据量。

一些方法包括:

  • gzip 响应
  • 对于每个 API 使用 DTO 技术而不是使用实体或模型中的完整列
  • 对字段使用简短的命名(不建议这种方式,因为返回的字段难以理解含义)

对于 Java Spring Boot,你可以在这里了解更多。

我正在参与2023腾讯技术创作特训营第四期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档