简体   繁体   English

Java web 应用程序在缓慢 MySQL 查询时停止

[英]Java web application stalls at slow MySQL queries

I have a web application written using Java servlets.我有一个使用 Java servlets 编写的 web 应用程序。 I am using Tomcat 7 as my servlet engine, but have used Glassfish previously and had the exact same issue.我使用 Tomcat 7 作为我的 servlet 引擎,但之前使用过 Glassfish 并且遇到了完全相同的问题。

The page in question has a "statistics" section that is updated every 5 minutes.有问题的页面有一个“统计”部分,每 5 分钟更新一次。 The statistics take about 30 seconds to generate due to the size of the MySQL tables involved.由于所涉及的 MySQL 表的大小,生成统计信息大约需要 30 秒。

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.呈现页面中的所有内容后,我刷新然后关闭 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.这样,用户无需等待大约 30 秒来加载页面,并且在页面已完全发送后更新统计信息。

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? Tomcat 是否应该能够使用另一个工作线程来处理请求,即使一个线程仍然很忙?

Thanks.谢谢。

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.将您的新统计数据放入表中,版本号为 current_version + 1。在进行所有计算之后。 Then a simple update stats_version set current_version = current_version + 1 will switch to using the new data.然后一个简单的update stats_version set current_version = current_version + 1将切换到使用新数据。 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.使用“切换”方法进行更新和“原子更新” - 更新“立即且完全”发生,因此用户看不到部分更改的数据集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM