0

在我的应用程序中,我有一段代码在其中发生以下活动

1.运行脚本 A 生成数据,生成一个文件
2.解析文件并从文件中读取数据
3.将数据存储在 3 个不同的表中,然后在存储之前将该日期的现有行标记为过时。
4.运行脚本 B
5.parse 由 B 生成的文件 6.将
数据存储在 2 个不同的表中,在存储之前将该日期的现有行标记为过时。
7.记录活动审计并发送邮件

现在这 7 个步骤将针对 10-12 个不同的实体并行完成。平台是 JAVA、Spring、Ibatis,并且正在以 ISOLATION LEVEL 为 READ COMMITTED 的新事务中为每个线程执行整个过程。线程由 ThreadPoolExecutor 管理,corepoolsize=maxPoolsize 为 10。表的大小约为 30K,每个表写入或更新的数据量约为 100 行。正在使用的数据库是 SQL 服务器。

问题在于没有@Transactional 符号,事情会按预期进行,但是当每个线程在事务中完成7 个步骤时,进程会卡住并且根本无法继续。在对处于挂起状态的查询进行调查时,发现有 3-4 个查询正在尝试执行第 3 步并陷入“将该日期的现有条目更新为陈旧的”。这也会导致锁升级,并且在 5-10 分钟后整个数据库被锁定,防止任何其他操作导致某种死锁。
请注意,不会发生实际的死锁,操作根本不会继续。
尝试的解决方案:在表上创建非聚集索引以帮助 SQL 服务器识别和锁定特定行。
请提出一些解决方案或问题的可能原因。

编辑

经过一番调查和分析,我想出了一个解决办法。生成所有数据后,我在线程末尾移动了步骤 3、6、7。所以这些步骤现在在一个单独的方法中完成,@Transaction 符号只应用于方法,而不是在事务中执行整个线程操作。此外,此方法已成为“同步”方法,因此即使有 10 个线程处于活动状态,任何时间点也只有一个 1 线程会写入 DB。因此这消除了多个线程尝试写入 DB 的后顾之忧同时。
我已经测试了这种方法,现在不存在之前看到的任何问题,但只是想知道是否使用@Transactional注释方法并使其同步很好,因为它会产生不良影响。此外,以同步方法写入数据库是一种好习惯。

对于那些对早期问题的实际原因感兴趣的人,我提到了一个可能的原因,可能是正确的,也可能不是正确的。线程卡住的一个可能原因是线程池执行程序的最大大小为 10 个线程,而 Apache DBCP 池的最大大小为 8 个 DB 连接。因此,当第一个线程进入事务并保持空闲超过 5 分钟(minEvicatableTime)时,它被逐出并将其连接提供给另一个线程。现在获得连接的其他线程无法写入数据,因为表被第一个线程锁定,而第一个线程无法完成,因为它没有数据库连接。

4

1 回答 1

0

表上应用了什么样的锁定方案?

我们有一个类似的应用程序,用户可以在表格中批量上传 Excel 表格。为了防止这种死锁,我们为该用户预订任务,直到他完成为止。在此期间没有其他用户可以使用相同的任务。

于 2013-08-19T10:43:44.317 回答