Java 使用Spring、MyBatis和;OracleDB
我在用Java与多个应用服务器执行数据库事务时遇到问题 脚本: 有两张桌子。锁定的文件信息&文件信息 1:FILE_INFO表包含文件ID(主)、文件名、用户ID、文件类型、数量等文件信息 2:LOCKED_FILE_INFO表包含FILEID(主)、FILENAME和TimeOfLock等信息 3:多个用户可以在文件信息和锁定文件信息表中输入文件列表或单个文件 4:在输入文件信息之前,我们在锁定的文件信息中锁定该特定文件,以便只有一个用户可以锁定该文件信息,然后进入文件信息表 5:如果多个用户正在为同一个文件执行输入,他们将得到“信息已被另一个用户锁定” 逻辑: 答:在文件信息表中输入之前,我们将检查锁定的文件信息表,以验证文件(例如:file100)是否已经存在 b:如果文件已存在(已锁定)-显示-“信息已被其他用户锁定” c:如果文件不存在(未锁定),则输入锁定文件信息,以便其他用户无法锁定文件,只有成功的用户才能进入文件信息表 d:在文件信息表中输入后,从锁定的文件信息表中删除锁定的文件 问题: 当多个用户试图在Lock\u file\u信息中同时锁定同一个文件时,我得到的是主密钥冲突异常 当我运行单个应用服务器时,不会发生这种情况。仅当多个应用程序服务器正在运行(至少5个)时才会发生这种情况 我尝试过的方法很少 答:使用同步 b:使用事务级隔离 但是,当多个用户试图同时插入锁定的文件信息表时,我仍然无法锁定特定的文件。但是,如果有至少1秒的延迟,那么我根本就没有问题Java 使用Spring、MyBatis和;OracleDB,java,spring,oracle,websphere,mybatis,Java,Spring,Oracle,Websphere,Mybatis,我在用Java与多个应用服务器执行数据库事务时遇到问题 脚本: 有两张桌子。锁定的文件信息&文件信息 1:FILE_INFO表包含文件ID(主)、文件名、用户ID、文件类型、数量等文件信息 2:LOCKED_FILE_INFO表包含FILEID(主)、FILENAME和TimeOfLock等信息 3:多个用户可以在文件信息和锁定文件信息表中输入文件列表或单个文件 4:在输入文件信息之前,我们在锁定的文件信息中锁定该特定文件,以便只有一个用户可以锁定该文件信息,然后进入文件信息表 5:如果多个用户
如有任何建议,将不胜感激。谢谢 发生问题是因为逻辑中存在错误。也就是说,由不同用户进行的两个并发事务可以成功地执行签入步骤
a
,并尝试插入LOCK\u FILE\u INFO
。显然,只有一个成功,第二个失败
当并行度改变时(当并发运行进程的数量改变时),运行进程中发生的单个事件的时间也会改变。因此,这些并发场景的行为可能会有所不同
你有几种方法来解决你的问题
处理主键冲突
您可以捕获异常并显示文件已锁定的消息。在这种情况下,检查锁记录是否存在是没有意义的。也就是说,您不需要执行步骤a
。只要插入一个锁记录,如果存在主键冲突-锁已经存在
用更新锁定
使用insert锁定的问题在于,检测冲突的唯一原因是通过约束冲突。如果您更改锁定策略以更新记录
首先,在创建file\u INFO
中的记录时,始终为LOCK\u file\u INFO
中的文件创建一条记录,或者在file\u INFO
表中存储有关锁定的信息(timeOfLock
列应该足够了,如果NULL
文件未锁定)
当需要锁定时,只需执行更新查询
update LOCK_FILE_INFO
set TimeOfLock = now()
where TimeOfLock is NULL
AND FILEID = some_id
然后,您需要检查记录是否已更新。每个修改语句都返回更新的记录数。要获得这个数字,只需从mybatis mapper中插入方法返回int
。如果记录已更新,则此事务成功获得锁,否则无法获得文件锁(可能已锁定,或者文件已删除,请参见下文)
请注意,这取决于some_id
是正确的文件id这一事实。文件可能在执行update语句之前被删除。在这种情况下,看起来文件被锁定了,但实际上它已经不存在了。实际上,这不是问题,因为锁定失败后,通常需要刷新UI以显示文件的更新状态,在这种情况下,您会检测到该文件已丢失
不起作用的选项
通过同步
使用synchronized
关键字(如果正确完成)进行同步仅对单个进程案例有帮助,因为在这种情况下,同步是使用进程内部的锁完成的。如果有多个JVM进程,每个进程都有自己的锁,同步将无法按预期工作
序列化隔离级别
序列化隔离级别在这种情况下不起作用,因为它无法帮助插入。如果在两个事务中插入两个具有相同密钥的记录,则无论隔离级别如何,都会出现相同的主键冲突。感谢您的建议,这非常有用:-)