当 运行 对 spring 批处理正在处理的 table 的 select 查询时,数据库查询挂起
Database query hangs when running a select query against a table that a spring batch process is working on
我有一个文件存储应用程序,它有两个服务(作业服务和文件服务)作为 spring 启动应用程序。当用户上传文件时,根据文件类型,它通过 spring 批处理作业进行处理,其缩略图和预览是使用 FFMpeg and/or ImageMagick 生成的。然后将这些数据写入数据库(目前正在 Microsoft SQL Server 2017 Developer 本地开发)。
较小的文件按预期工作,但我想通过发送一堆较大的音频和视频文件来测试应用程序,并开始刷新文件页面以查看文件是否已处理。然而,在几次刷新后,UI 一直停留在 "loading" 状态,直到 spring 批处理作业结束,然后按预期显示结果。
我 运行 进行了相同的测试并检查了网络选项卡,发现为检索文件列表而进行的调用处于 "pending" 状态。它停留在该阶段,直到批处理过程的其余部分完成并返回成功 (200)。
在 web 服务端进行一些调试后,我发现文件服务应用程序卡在了以下行:
List<Asset> allAssets = jdbcTemplate.query("SELECT asset_id, asset_extension, asset_import_date, asset_imported_by_username, asset_name, asset_path, asset_preview_path, asset_thumbnail_path, asset_type FROM assets", new AssetRowMapper());
所以在我的场景中,当我刷新文件页面时,我试图访问资产 table,因为 spring 批处理作业也在相同的 table 上工作以插入和更新每个文件的相关数据。我想也许插入和更新查询以某种方式优先并从我的 select 查询中锁定 table。所以我从资产 table 创建了一个视图并将查询更改为:
List<Asset> allAssets = jdbcTemplate.query("SELECT asset_id, asset_extension, asset_import_date, asset_imported_by_username, asset_name, asset_path, asset_preview_path, asset_thumbnail_path, asset_type FROM assets_vw", new AssetRowMapper());
不幸的是,这没有用,我得到了同样的结果。
要查看此问题是来自应用程序端(我的代码)还是数据库端,我 运行 进行了相同的测试,但我 运行 通过 [=46= 手动进行了相同的查询] 我的数据库上的 Management Studio。有趣的是,在几次成功的查询之后(正如我在 UI 上看到的那样),我得到了相同的结果,查询停留在 "executing" 阶段,直到其余的 spring 批处理作业完成。
看来是数据库方面的问题
我检查了我的数据库的最大连接数(如各种帖子中所建议的),它已经是默认值 0(无限制)。
此时我不确定我的数据库(或我的代码)出了什么问题。任何帮助将不胜感激。
我同意@scsimon 的评论,即症状是由于阻塞造成的。 SQL 服务器在 READ COMMITTED
隔离级别中默认使用锁定,因此您的 SELECT
查询(检索所有行)在遇到正在进行的上传行时可能会被阻止尚未提交。
考虑启用 READ_COMMITTED_SNAPSHOT
数据库选项,以便在不更改应用程序代码的情况下使用行版本控制而不是锁定在 READ COMMITTED
隔离级别。这是一个可行的解决方案,除非您的应用程序特别依赖于锁定行为,例如将 SQL 服务器表用作队列时。 READ_COMMITTED_SNAPSHOT
的其他注意事项是增加 tempdb 使用(用于版本存储)和每行大小增加 14 字节。
我要补充一点,READ_COMMITTED_SNAPSHOT
在 Azure SQL 数据库中默认启用,但在本地版本中不启用。
问题可能是您的大批量插入是在单个事务中执行的。对于处理插入的服务,我会检查代码以确保不是这种情况。如果是,则不需要所有插入都是全有或全无操作。您可以使单个文件的所有插入成为单个事务的一部分,而不是所有文件都成为单个事务的一部分。这将确保来自您的 SELECT 语句的 READ LOCKS 将有机会进入队列并更及时地处理。
我有一个文件存储应用程序,它有两个服务(作业服务和文件服务)作为 spring 启动应用程序。当用户上传文件时,根据文件类型,它通过 spring 批处理作业进行处理,其缩略图和预览是使用 FFMpeg and/or ImageMagick 生成的。然后将这些数据写入数据库(目前正在 Microsoft SQL Server 2017 Developer 本地开发)。
较小的文件按预期工作,但我想通过发送一堆较大的音频和视频文件来测试应用程序,并开始刷新文件页面以查看文件是否已处理。然而,在几次刷新后,UI 一直停留在 "loading" 状态,直到 spring 批处理作业结束,然后按预期显示结果。
我 运行 进行了相同的测试并检查了网络选项卡,发现为检索文件列表而进行的调用处于 "pending" 状态。它停留在该阶段,直到批处理过程的其余部分完成并返回成功 (200)。
在 web 服务端进行一些调试后,我发现文件服务应用程序卡在了以下行:
List<Asset> allAssets = jdbcTemplate.query("SELECT asset_id, asset_extension, asset_import_date, asset_imported_by_username, asset_name, asset_path, asset_preview_path, asset_thumbnail_path, asset_type FROM assets", new AssetRowMapper());
所以在我的场景中,当我刷新文件页面时,我试图访问资产 table,因为 spring 批处理作业也在相同的 table 上工作以插入和更新每个文件的相关数据。我想也许插入和更新查询以某种方式优先并从我的 select 查询中锁定 table。所以我从资产 table 创建了一个视图并将查询更改为:
List<Asset> allAssets = jdbcTemplate.query("SELECT asset_id, asset_extension, asset_import_date, asset_imported_by_username, asset_name, asset_path, asset_preview_path, asset_thumbnail_path, asset_type FROM assets_vw", new AssetRowMapper());
不幸的是,这没有用,我得到了同样的结果。
要查看此问题是来自应用程序端(我的代码)还是数据库端,我 运行 进行了相同的测试,但我 运行 通过 [=46= 手动进行了相同的查询] 我的数据库上的 Management Studio。有趣的是,在几次成功的查询之后(正如我在 UI 上看到的那样),我得到了相同的结果,查询停留在 "executing" 阶段,直到其余的 spring 批处理作业完成。
看来是数据库方面的问题
我检查了我的数据库的最大连接数(如各种帖子中所建议的),它已经是默认值 0(无限制)。
此时我不确定我的数据库(或我的代码)出了什么问题。任何帮助将不胜感激。
我同意@scsimon 的评论,即症状是由于阻塞造成的。 SQL 服务器在 READ COMMITTED
隔离级别中默认使用锁定,因此您的 SELECT
查询(检索所有行)在遇到正在进行的上传行时可能会被阻止尚未提交。
考虑启用 READ_COMMITTED_SNAPSHOT
数据库选项,以便在不更改应用程序代码的情况下使用行版本控制而不是锁定在 READ COMMITTED
隔离级别。这是一个可行的解决方案,除非您的应用程序特别依赖于锁定行为,例如将 SQL 服务器表用作队列时。 READ_COMMITTED_SNAPSHOT
的其他注意事项是增加 tempdb 使用(用于版本存储)和每行大小增加 14 字节。
我要补充一点,READ_COMMITTED_SNAPSHOT
在 Azure SQL 数据库中默认启用,但在本地版本中不启用。
问题可能是您的大批量插入是在单个事务中执行的。对于处理插入的服务,我会检查代码以确保不是这种情况。如果是,则不需要所有插入都是全有或全无操作。您可以使单个文件的所有插入成为单个事务的一部分,而不是所有文件都成为单个事务的一部分。这将确保来自您的 SELECT 语句的 READ LOCKS 将有机会进入队列并更及时地处理。