Java Web 应用程序因 MySQL 查询缓慢而停止

发布于 2024-11-29 08:29:47 字数 408 浏览 0 评论 0原文

我有一个使用 Java servlet 编写的 Web 应用程序。我使用 Tomcat 7 作为我的 servlet 引擎,但之前使用过 Glassfish 并且遇到了完全相同的问题。

该页面有一个“统计”部分,每 5 分钟更新一次。由于涉及的 MySQL 表的大小,生成统计信息大约需要 30 秒。

当我加载页面时,我会显示缓存的统计信息。渲染页面中的所有内容后,我刷新并关闭输出流。然后我更新统计数据。这样,用户无需等待大约 30 秒即可加载页面并在页面完全发送后更新统计信息。

问题是,如果我在运行查询时刷新页面,则在查询完成之前页面不会加载,这意味着虽然初始用户没有任何延迟,但之后会有很长的延迟。

为什么应用程序实际上停滞了?即使一个线程仍然忙碌,Tomcat 是否应该能够使用另一个工作线程来处理请求?

谢谢。

I have a web application written using Java servlets. I am using Tomcat 7 as my servlet engine, but have used Glassfish previously and had the exact same issue.

The page in question has a "statistics" section that is updated every 5 minutes. The statistics take about 30 seconds to generate due to the size of the MySQL tables involved.

When I get a page load, I show the cached statistics. After everything in the page has been rendered, I flush and then close the output stream. I then update the statistics. This way, no user has to ever wait ~30 seconds for the page to load and the statistics update after the page has already been completely sent.

The problem is that if I refresh the page while it's running the query, the page doesn't load until the query has completed, which means that although the initial user doesn't have any delay, after that there is a long delay.

Why is the application effectively stalling? Shouldn't Tomcat be able to use another worker thread to handle the request, even though one thread is still busy?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

╰沐子 2024-12-06 08:29:47

可能发生的情况是您的数据在更新时被“锁定更新” - 这取决于数据的重新计算方式。

解决此问题的一个好方法是将新计算放入单独的数据区域,然后在全部完成后切换到使用新数据。实现此目的的一种方法是使用数据库视图和版本号,如下所示:

create table my_statistics (
  id int not null primary key auto_increment,
  version int not null,
  -- other columns with your data
);

create table stats_version (current_version int); -- holds just one row

create view stats as
select * 
from stats_version v
join my_statistics s on s.version = v.current_version);

将新统计数据放入版本号为 current_version + 1 的表中。完成所有计算后。然后,简单的 update stats_version set current_version = current_version + 1 将切换为使用新数据。最后一条语句只需几毫秒即可执行,因此锁定等待时间很小。

切换后,您可以删除旧的统计信息以节省空间。

使用“切换”方法进行更新和“原子更新”——更新“立即且完全”发生,因此用户不会看到部分更改的数据集。

What might be happening is your data is being "locked for update" while the update is taking place - it depends on exactly how the data is being recalculated.

A good way to work around this is to make the new calculation into a separate data area, then switch over to using the new data after it's all done. One way to implement this is using a database view and a version number, like this:

create table my_statistics (
  id int not null primary key auto_increment,
  version int not null,
  -- other columns with your data
);

create table stats_version (current_version int); -- holds just one row

create view stats as
select * 
from stats_version v
join my_statistics s on s.version = v.current_version);

Put your new stats into the table with a version number of current_version + 1. After all calculations have been made. Then a simple update stats_version set current_version = current_version + 1 will switch to using the new data. This last statement takes just milliseconds to execute, so locking waits are tiny.

After switching, you can delete the old stats to save space.

Using the "switch" approach makes the update and "atomic update" - the update happens "instantly and completely", so users don't see a partially changed dataset.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文