java - 使用 Spring、MyBatis 和 OracleDB 在 Java 中使用多个应用程序服务器进行数据库事务
问题描述
我在使用多个应用程序服务器在 Java 中执行数据库事务时遇到问题。
设想:
有两张桌子。LOCKED_FILE_INFO & FILE_INFO
1:FILE_INFO表包含FILEID(Primary)、FILENAME、USERID、FILETYPE、QTY等文件信息
2:LOCKED_FILE_INFO表包含FILEID(Primary)、FILENAME和TimeOfLock等信息
3:多个用户可以在FILE_INFO & LOCKED_FILE_INFO 表中输入文件列表或单个文件。
4:在进入 FILE_INFO 之前,我们将特定文件锁定在 LOCKED_FILE_INFO 中,这样只有 1 个用户可以锁定该 FILE 信息,然后进入 FILE_INFO 表。
5:如果多个用户对同一个文件执行条目,他们将得到-“信息已被另一个用户锁定”。
逻辑:
a: 在 FILE_INFO 表中进行条目之前,我们将检查 LOCKED_FILE_INFO 表以验证文件(例如:file100)是否已经存在
b:如果文件已经存在(LOCKED)-显示-“信息已被另一个用户锁定”。
c:如果文件不存在(NOT LOCKED),则进入LOCK_FILE_INFO,使其他用户无法锁定文件,只有成功的用户才能进入FILE_INFO表。
d:一旦我们进入 FILE_INFO 表,就从 LOCKED_FILE_INFO 表中删除锁定文件
问题:
当多个用户尝试在 LOCK_FILE_INFO 中同时锁定同一个文件时,我会收到 PRIMARY_KEY 违规异常这在我运行单个应用程序服务器时不会发生。这仅在运行多个应用程序服务器(至少 5 个)时发生
我尝试了几种方法 a:使用同步 b:使用事务级隔离
但是,当多个用户尝试同时插入 LOCKED_FILE_INFO 表时,我仍然无法锁定特定文件。但是,如果有至少 1 秒的延迟,那么我根本不会遇到问题。
任何建议将不胜感激。谢谢 !
解决方案
出现问题是因为逻辑中存在竞争条件。即不同用户进行的两个并发事务可能会成功执行 check in stepa
并尝试插入到LOCK_FILE_INFO
. 显然只有一个成功,第二个会失败。
当并行度发生变化时(当同时运行的进程数量发生变化时),正在运行的进程中发生的各个事件的时间也会发生变化。因此,此类并发场景的行为可能会有所不同。
您有多种选择来解决您遇到的问题。
处理主键违规
您可以捕获异常并显示文件已锁定的消息。在这种情况下,检查锁记录是否存在是没有意义的。那就是您不需要执行 step a
。只需插入一条锁记录,如果存在主键违规 - 锁已经存在。
锁定更新
使用插入锁定的问题是检测冲突的唯一原因是通过违反约束。如果您更改锁定策略以便更新记录。
首先,要么总是在创建记录时为文件创建一条记录,要么LOCK_FILE_INFO
存储FILE_INFO
有关锁定FILE_INFO
表的信息(timeOfLock
列应该足够,如果它是NULL
文件未锁定)。
当需要加锁时,执行更新查询即可
update LOCK_FILE_INFO
set TimeOfLock = now()
where TimeOfLock is NULL
AND FILEID = some_id
然后您需要检查记录是否已更新。每个修改语句都会返回更新记录的数量。要获得这个数字,只需int
从 mybatis 映射器中的 insert 方法返回。如果记录被更新,则该事务成功获得锁,否则无法获得文件锁(要么已经被锁定,要么文件已被删除,见下文)。
some_id
请注意,这依赖于正确的文件 ID的事实。在您执行更新语句之前可能会删除文件。在这种情况下,它看起来像文件被锁定,但实际上它已经消失了。实际上,这不是问题,因为在锁定失败后,您通常需要刷新 UI 以显示文件的更新状态,在这种情况下,您会检测到该文件已消失。
不起作用的选项
通过 synchronized 进行同步
使用synchronized
关键字进行同步(如果正确完成)仅对单进程情况有帮助,因为在这种情况下,同步是使用进程内部的锁完成的。如果有多个 JVM 进程,每个进程都有自己的锁,同步将无法按预期工作。
序列化隔离级别
在这种情况下,序列化隔离级别将不起作用,因为它无法帮助插入。如果在两个事务中插入具有相同键的两条记录,则无论隔离级别如何,都会违反相同的主键。
推荐阅读
- c# - 充气城堡 C# prime256v1 ECDSA 签名
- java - FlowPane 不占用其外部 HBox 宽度的 100%
- docusignapi - 为什么 Docusign 看不到我的重定向 URI?
- visual-studio-code - 尝试在 Code:OSS 上下载 Import Cost 扩展
- python - 由于某些特征结构问题,PyCharm 中的 Behave Runner 出错-behave.parser.ParserError:
- angular - *NgIf 异步对象触发 else 部分
- angular - Socket.Io 没有在 Chrome 中触发任何事件
- c - 为什么我的 if 语句函数没有填充我的变量 (C)?
- json - 使用 React 显示来自 API 的数据
- android - 如何在 React Native 中生成用于本地分发的 APK?