我有一个文件存储应用程序,它具有两个服务(作业服务和文件服务)作为春季启动应用程序。用户上载文件时,根据文件类型,它会通过春季批处理作业进行处理,其缩略图和预览是使用FFMpeg和/或ImageMagick生成的。然后将这些数据写入数据库(当前在Microsoft SQL Server 2017 Developer本地进行开发)。
较小的文件按预期工作,但我想通过发送一堆较大的音频和视频文件来测试应用程序,并开始刷新文件页面以查看文件是否已处理。但是,经过几次刷新后,UI停留在“加载”状态,直到春季批处理作业结束,然后按预期显示结果。
我进行了相同的测试,并检查了“网络”选项卡,并注意到为检索文件列表而进行的调用处于“待处理”状态。它一直停留在该阶段,直到其余批处理过程完成并成功返回为止(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());
因此,在我的场景中,当我刷新文件页面时,我试图访问资产表,因为弹簧批处理作业也在同一表上工作,以插入和更新每个与文件相关的数据。我认为插入和更新查询可能会以某种方式优先,并从我的选择查询中锁定表。因此,我从资产表创建了一个视图,并将查询更改为:
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());
不幸的是,这没有用,我得到了相同的结果。
要查看此问题是源于应用程序端(我的代码)还是数据库端,我运行了相同的测试,但是我通过数据库上的SQL Management Studio手动运行了相同的查询。有趣的是,在几次成功的查询之后(正如我在UI上看到的那样),我得到了相同的结果,查询一直停留在“执行”阶段,直到其余的春季批处理作业完成。
所以看来问题出在数据库方面。
我检查了数据库上的最大连接数(如在各种帖子中所建议的),它已经是默认值0(无限制)。
目前,我不确定数据库(或代码)出了什么问题。任何帮助将不胜感激。
答案 0 :(得分:3)
我同意@scsimon的评论,即症状是由于阻塞所致。 SQL Server默认在READ COMMITTED
隔离级别使用锁定,因此当SELECT
查询(检索所有行)遇到一行尚未提交的正在进行中的上载时,很可能被阻止
请考虑打开READ_COMMITTED_SNAPSHOT
数据库选项,以便在不更改应用程序代码的情况下使用行版本控制而不是锁定在READ COMMITTED
隔离级别。除非您的应用程序特别依赖于锁定行为(例如,将SQL Server表用作队列时),否则这是一个可行的解决方案。 READ_COMMITTED_SNAPSHOT
的其他考虑因素包括增加的tempdb使用量(用于版本存储)和每行大小增加14字节。
我要添加的是,READ_COMMITTED_SNAPSHOT
在Azure SQL数据库中默认处于启用状态,但在本地版本中未启用。
答案 1 :(得分:1)
问题可能是您的大量插入操作正在单笔交易中执行。对于处理插入内容的服务,我将检查代码以确保不是这种情况。如果是这样,则不需要所有插入都为全部或全部操作。您可以将单个文件的所有插入都作为单个事务的一部分,而不是将所有文件都作为单个事务的一部分。这样可以确保来自SELECT语句的READ LOCKS有机会进入队列并得到更及时的处理。