简体   繁体   中英

Solve Concurrent Update/Delete Statements Java Oracle

The problem I have right now deals with the SQL UPDATE and DELETE statements concurrently. If the program is only called one after the other then there is no problems, however, if two people decide to run the program it might fail.

What my program does:

A program about food which all has a description and a date of when that description was made. As people enter the description of the food it gets entered into a database where you can quickly retrieve the description. If the description is lets say 7 days old then we delete it cause its outdated. However, if a user enters a food already in the database with a different description then we update it and change the date. The deletion happens after the update/insertion (those that dont need updating will be inserted and then the program checks for outdated things in the database and deletes them).

The problem:

Two people run the program and right as one person is trying to update a food, the other clears it out with the deletion cause it just finished. The update will not happen, and the program will continue with the rest of the updates (<- I read that this is because my driver doesn't stop. Some drivers stop updating if there is an error).

What I want to do:

I want my program to stop at the bad update or grab that food position and restart the process/thread. The restarting will include sorting out which foods needs to be updated or inserted. Therefore, the bad record will be moved into the inserting method and not the update. The update will continue where it left off. And all's well.

I know this is not the only way, so different methods on how to solve this problem is welcome. I have looked up that you can use an upsert statement, but that also has race conditions. (Question about the upsert statement: If I make the upsert method synchronized will it not have race conditions?)

Thanks

Set transaction level to serializable in java code. Then your statements should look like:

 update food_table set update_time = ? where ....
 delete from food_table where update_time < ?

You may get an serializable exception in either case. In the case of the update you will need to reinsert the entry. In the second case, just ignore and run again.

There are different pratical solutions to your problem depending on jout jdbc connection management.

If the application is a client server one and it uses a dedicated persistent connection (ie it opens a jdbc connection at program startup and it closes when the program shutdowns) for each client you can use a select for update statement. You must issue a select for update when displaying records to the user and when the user does its action you do what is needed and commit. This approach serializes the dabatabase operations and if you show and lock multiple records it may not be feasible .

A second approach is usable when you have a web application with a connection pool or when you don't have a dedicated connection you can use for the read and update/delete operation. In this case you have this scenario

user 1 selects its data with jdbc connection 1

user 2 selects its data (the same as user 1) with jdbc connection 2

user 2 submit data causing some deletions with jdbc connection 3

user 1 submit data and lot an update beacuse the data was deleted with jdbc connection 2

Since you cannot realy on the same jdbc connection to lock the data you read, you can issue a select for update before updating the data and check if there are data. If you have the data you can update them (and they will not be deleted by other sessions since every delete command on the same data is waiting your select for update to terminate); if you don't have the data because they where deleted during user display you must reinsert them. You delete statement must have a filter on the date column that represent the last update.

You can use other approaches and avoid the select for update using for example an

  update food-table set last_update=? where id=? and last_update=<the last update you have in java  program> 

and you must check that the update statement did update a row (in jdbc executeUpdate returns the number of rows modified, but you did not specifiy if you are using "plain" JDBC or some sort of framework) and if it did not update a row you must isse the insert statement.

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