Java 中 N+1 问题的集成测试

N+1问题:N+1问题是指在使用关系型数据库时,在获取一组对象及其关联对象时,产生额外的数据库查询的问题。其中N表示要获取的主对象的数量,而在获取每个主对象的关联对象时,会产生额外的1次查询。,N+1问题是很多项目中的通病。遗憾的是,直到数据量变得庞大时,我们才注意到它。不幸的是,当处理 N + 1 问题成为一项难以承受的任务时,代码可能会达到了一定规模。,在这篇文章中,我们将开始关注以下几点问题:,假设我们正在开发管理动物园的应用程序。在这种情况下,有两个核心实体:Zoo和Animal。请看下面的代码片段:,现在我们想要检索所有现有的动物园及其动物。看看ZooService下面的代码。,此外,我们要检查一切是否顺利进行。简单的集成测试:,测试成功通过。但是,如果记录 SQL 语句,会注意到以下几点:,如所见,我们select对每个 present 都有一个单独的查询Zoo。查询总数等于所选动物园的数量+1。因此,这是N+1问题。,这可能会导致严重的性能损失。尤其是在大规模数据上。,当然,我们可以自行运行测试、查看日志和计算查询次数,以确定可行的性能问题。无论如何,这效率很低。。,有一个非常高效的库,叫做datasource-proxy。它提供了一个方便的 API 来javax.sql.DataSource使用包含特定逻辑的代理来包装接口。例如,我们可以注册在查询执行之前和之后调用的回调。该库还包含开箱即用的解决方案来计算已执行的查询。我们将对其进行一些改动以满足我们的需要。,首先,将库添加到依赖项中:,现在创建QueryCountService. 它是保存当前已执行查询计数并允许您清理它的单例。请看下面的代码片段。,将SingleQueryCountHolder所有QueryCount对象存储在常规ConcurrentHashMap.,API 提供了两种方法。该get方法返回当前执行的查询数量,同时clear将计数设置为零。,现在我们需要注册QueryCountService以使其从 收集数据DataSource。在这种情况下,BeanPostProcessor 接口就派上用场了。请看下面的代码示例。,如您所见,这个想法很简单。如果一个 bean 是DataSource,则将其包裹起来ProxyDataSourceBuilder并将QUERY_COUNT_HOLDER值作为QueryCountStrategy.,最后,我们要断言特定方法的已执行查询量。看看下面的代码实现:,该代码很简单:,此外,您还注意到了一个附加条件。如果提供的计数类型小于零,则跳过断言。不关心其他查询计数时,这很方便。,该类Expectation只是一个常规数据结构。看下面它的声明:,让我们看看它是如何工作的。首先,我在之前的 N+1 问题案例中添加了查询断言。看下面的代码块:,如果我们重新运行测试,我们将得到下面的输出。,所以,确实有效。我们设法自动跟踪 N+1 问题。是时候用 替换常规选择了JOIN FETCH。请看下面的代码片段。,让我们再次运行测试并查看结果:,Java 中 N+1 问题的集成测试,这意味着正确地跟踪了 N + 1 个问题。此外,如果查询数量等于预期数量,则它会成功通过。,事实上,定期测试可以防止 N+1 问题。这是一个很好的机会,可以保护那些对性能至关重要的代码部分。

文章版权声明

 1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/26569.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年6月23日
下一篇 2023年7月15日