简体   繁体   中英

Database Transaction in Java with Multiple Application Servers using Spring, MyBatis & OracleDB

I am having a problem while performing a Database Transaction in Java with multiple Application Servers.

Scenario:

There are two tables. LOCKED_FILE_INFO & FILE_INFO

1: FILE_INFO table contains the information of Files such as FILEID(Primary), FILENAME, USERID, FILETYPE, QTY

2: LOCKED_FILE_INFO table contains the info such as FILEID(Primary), FILENAME and TimeOfLock

3: There can be list of FILEs or single FILE to be entered in the FILE_INFO & LOCKED_FILE_INFO Table by multiple users.

4: Before, making entry in the FILE_INFO we are locking that particular file in the LOCKED_FILE_INFO so that only 1 user can lock that FILE info and then enter into the FILE_INFO Table.

5: If multiple users are performing the entry for the same FILE, they will get - "Information already locked by another user".

Logic:

a: Before making entry in the FILE_INFO table, we will check the LOCKED_FILE_INFO table to verify if a file (eg: file100) already exists

b: If the File already exists (LOCKED) - Display -"Information already locked by another user".

c: If the File doesn't exist (NOT LOCKED), then Make an entry to the LOCK_FILE_INFO so that another user can't lock the file and only the successful user can only enter into the FILE_INFO Table.

d: Delete the Locked file from the LOCKED_FILE_INFO Table once we enter in the FILE_INFO table

Problem:

When Multiple users try to Lock the Same file at the same time in the LOCK_FILE_INFO, then I'm getting PRIMARY_KEY violation exception This is not happening when I run a Single Application Server. This is only happening when Multiple Application Servers are running (at least 5)

There are few approaches I tried a: Using Synchronization b: Using Transactional Level Isolation

However, I'm still not able to Lock a particular file when multiple users try to insert into the LOCKED_FILE_INFO table at the exact same time. However, if there is a Delay of at least 1 seconds, then I'm not getting the problem at all.

Any suggestions will be greatly appreciated. Thanks !

The problem happens because there is a race condition in the logic. Namely, two concurrent transactions made by different users may successfully execute check in step a and would try to insert to LOCK_FILE_INFO . Obviously only one succeeds and the second would fail.

When the degree of parallelism changes (when the number of concurrently running processes changes) the timing of individual events happening in running process(es) also change. So the behaviour of such concurrent scenarios may be different.

You have several options how to approach the problem you have.

Handle Primary Key violation

You can catch the exception and show the message that file is already locked. In this case it does not make sense to check if the lock record exists. That is you don't need to execute step a . Just insert a lock record and if there's primary key violation - the lock is already there.

Lock with update

The problem with locking using insert is that the only reason to detect conflict is via constraint violation. If you change locking strategy so that you update a record instead.

First, either always create a record for file in LOCK_FILE_INFO when the record in FILE_INFO is created or store information about lock in FILE_INFO table ( timeOfLock column should be enough, if it is NULL the file is not locked).

When you need to lock, just execute the update query

update LOCK_FILE_INFO
set TimeOfLock = now()
where TimeOfLock is NULL
   AND FILEID = some_id

Then you need to check if a record was updated. The number of updated records is returned by every modification statement. To get this number just return int from you insert method in mybatis mapper. If the record was updated then this transaction successfully obtained the lock, otherwise the file lock cannot be obtained (either it is locked already or file has been deleted, see below).

Note that this relies on the fact that some_id is a correct file id. It may happen that file was removed just before you executed the update statement. In this case it would look like file is locked, but in reality it is gone already. In practice this is not a problem as after unsuccessful lock you usually need to refresh UI to display the updated state of the file and in this case you would detect that file is gone.

Options That Do Not Work

Synchronization via synchronized

Synchronization using synchronized keyword (if done properly) would help only for single process case, because in this case the synchronization is done using the lock which is internal to the process. If there are multiple JVM processes each will have its own lock and the synchronization will not work as intended.

Serialized Isolation Level

Serialized isolation level would not work in this case because it cannot help with inserts. If you insert two records with the same key in two transactions you get the same primary key violation regardless of isolation level.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM