简体   繁体   English

解决并发更新/删除语句Java Oracle

[英]Solve Concurrent Update/Delete Statements Java Oracle

The problem I have right now deals with the SQL UPDATE and DELETE statements concurrently. 我现在遇到的问题是同时处理SQL UPDATEDELETE语句。 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. 如果描述是旧的7天,那么我们deletedelete使其过时。 However, if a user enters a food already in the database with a different description then we update it and change the date. 但是,如果用户使用不同的描述输入数据库中已有的食物,则我们将对其进行update并更改日期。 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. upsert您可以使用upsert语句,但这也有竞争条件。 (Question about the upsert statement: If I make the upsert method synchronized will it not have race conditions?) (关于upsert语句的问题:如果我使upsert方法同步,它将不会有竞争条件吗?)

Thanks 谢谢

Set transaction level to serializable in java code. 在Java代码中将事务级别设置为可序列化。 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. 根据jout jdbc连接管理,对您的问题有不同的实用解决方案。

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. 如果该应用程序是一个客户端服务器,并且它对每个客户端使用专用的持久连接(即,它在程序启动时打开jdbc连接,并在程序关闭时关闭),则可以使用select for update语句。 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 . 这种方法序列化了dabatabase操作,如果显示并锁定了多个记录,则可能不可行

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. 当您的Web应用程序带有连接池或没有专用连接时,可以使用第二种方法进行读取和更新/删除操作。 In this case you have this scenario 在这种情况下,您有这种情况

user 1 selects its data with jdbc connection 1 用户1通过jdbc连接1选择其数据

user 2 selects its data (the same as user 1) with jdbc connection 2 用户2通过jdbc连接2选择其数据(与用户1相同)

user 2 submit data causing some deletions with jdbc connection 3 用户2使用jdbc连接3提交导致某些删除的数据

user 1 submit data and lot an update beacuse the data was deleted with jdbc connection 2 用户1提交数据并进行大量更新,因为该数据已通过jdbc连接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. 既然你不能真的在同一个JDBC连接锁定您读取数据,你可以发出一个select for update更新数据前,检查是否有数据。 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. 您的delete语句在date列上必须具有表示最后更新的过滤器。

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. 并且必须检查update语句是否确实更新了一行(在jdbc中,executeUpdate返回已修改的行数,但是如果使用的是“纯” JDBC或某种框架,则没有指定),并且它没有更新任何行您必须发出插入语句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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