Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] non-repeatable read in combination with a delete

What is occurring in the two cases is the following,

Case 1
- thread 1 reads parent
- thread 2 deletes parent
- thread 1 creates new child and registers parent
--- registerObject can be called for new or existing objects, and existence
check is performed
--- the default existence check, checks the cache, since the parent was
removed, it is not in the cache
--- so assumed to be a new object, and is inserted

Case 2
- thread 1 reads parent
- thread 1 creates new child and registers parent
--- registerObject can be called for new or existing objects, and existence
check is performed
--- the default existence check, checks the cache, since the parent still
exists, it is in the cache
--- so assumed to be an existing object
- thread 2 deletes parent
- thread 1 commits, child is inserted with foreign key to parent which was
deleted, so constraint error occurs


If you instead use registerExistingObject, then the parent will be
registered as an existing object in both cases, and you will get the same
constraint error.
You could have also read the parent in the context of the UnitOfWork,
instead of just calling registerObject on it, this would be more correct as
it respects the UnitOfWork transaction isolation.

Basically in a concurrent situation there is no magical solution, you must
use some form of locking.
If you use pessimistic locking on the read for the parent in the context of
the transaction, then the second thread would always get null for the
parent, so would then need to decide weather it should create a new object,
or do something else.

Ideally optimistic locking would also handle this situation, but currently
EclipseLink does not check the version field on registerObject, it is only
checked on update/delete or merge.  If you used merge() instead of
registerObject you should get a lock error if you are using version locking. 
I think that EclipseLink should probably check the version on
registerObject, so you could log a bug for this.  You could also configure
your descriptor's DoesExistQuery to determine the existence of an object by
the value of its version field, this would be more efficient and cause the
lock exception to be raised.





Huub Sepers-2 wrote:
> 
> 
> James, 
> 
> Thanks for your reply.
> 
>>Your removeCompany code is wrong.  Before removing an object you must
>>remove
>>any references to it.  Normally you would get a constraint error, but
> you
>>have the constraint defined in the other direction.
> The removeCompany code is normally executed in a different thread after
> all employees are removed. Furthermore in the testcase there are no
> employees when the removeCompany code is executed. Could you explain
> which references you are referring to?
> 
>>If you are concerned about concurrency, then you should also be using
>>optimistic version locking.  This would allow the  version of the
> company >to be checked so that it knows it is an existing object.
> What I want and what I expected was that both testcases would give the
> same constraint error. In the actual application code optimistic locking
> is used but has no effect on the fact that there is a different outcome
> depending on when the registerObject of the Company is executed.
> How would version checking help for a deleted Object?
> 
>>This is also related to your usage of registerObject instead of
>>registerExistingObject and your does-exist policy.  The default does
> exist
>>is to check the cache, as it assumes the cache is correct.  But your
> remove
>>has corrupted the cache, you could set another type of existence check
> if
>>you intend to corrupt your cache.
> registerExistingObject seems relevant. Both testcases give the same
> constraint error when using registerExistingObject. This is what I want
> and excpted. However I do not yet understand how the remove has
> corrupted the cache. Could you please explain?
> 
> Greetings,
> Huub Sepers
> 
> 
> -----Original Message-----
> From: eclipselink-users-bounces@xxxxxxxxxxx
> [mailto:eclipselink-users-bounces@xxxxxxxxxxx] On Behalf Of James
> Sutherland
> Sent: Wednesday, January 19, 2011 3:15 PM
> To: eclipselink-users@xxxxxxxxxxx
> Subject: Re: [eclipselink-users] non-repeatable read in combination with
> a delete
> 
> 
> Your removeCompany code is wrong.  Before removing an object you must
> remove
> any references to it.  Normally you would get a constraint error, but
> you
> have the constraint defined in the other direction.
> 
> If you are concerned about concurrency, then you should also be using
> optimistic version locking.  This would allow the  version of the
> company to
> be checked so that it knows it is an existing object.
> 
> This is also related to your usage of registerObject instead of
> registerExistingObject and your does-exist policy.  The default does
> exist
> is to check the cache, as it assumes the cache is correct.  But your
> remove
> has corrupted the cache, you could set another type of existence check
> if
> you intend to corrupt your cache.
> 
> 
> Huub Sepers-2 wrote:
>> 
>> Hi,
>> 
>>  
>> 
>> I have a question about a non-repeatable read scenario whereby a
> parent
>> entity is deleted.
>> 
>>  
>> 
>> See the enclosed testcase.
>> 
>>  
>> 
>> The following scenario:
>> 
>>  
>> 
>> We have 2 entities with a parent-child relationship, Company-Employee.
>> Suppose the parent is removed in one thread wile another thread
> inserts
>> a child for the same parent.
>> It appears that different things happen according to timing issues.
>> 
>>  
>> 
>> It appears that when the parent is removed (commit) just after it has
>> been found but just before it is registered then the parent will be
>> inserted as a new object with the same primary key.
>> 
>> See testcase "testWR".
>> 
>> When the parent is removed after it has been registered an ORA-02291
>> (parent key not found) will occur.
>> 
>> See testcase "testWR2"
>> 
>>  
>> 
>> The testcases are single threaded but illustrate the point.
>> 
>>  
>> 
>> I have tested this with Eclipselink 1.1.4, 1.1.2, 1.1.1 and 1.2.0.
>> 
>>  
>> 
>> Questions:
>> 
>> I would expect the ORA-02291 to occur in both cases?
>> 
>> What can I do to get a consistent error in both cases?
>> 
>>  
>> 
>> Met vriendelijke groet,
>> 
>> Huub Sepers
>> 
>> Software Engineer
>> 
>> 
> 
> 


-----
http://wiki.eclipse.org/User:James.sutherland.oracle.com James Sutherland 
http://www.eclipse.org/eclipselink/
 EclipseLink ,  http://www.oracle.com/technology/products/ias/toplink/
TopLink 
Wiki:  http://wiki.eclipse.org/EclipseLink EclipseLink , 
http://wiki.oracle.com/page/TopLink TopLink 
Forums:  http://forums.oracle.com/forums/forum.jspa?forumID=48 TopLink , 
http://www.nabble.com/EclipseLink-f26430.html EclipseLink 
Book:  http://en.wikibooks.org/wiki/Java_Persistence Java Persistence 
Blog:  http://java-persistence-performance.blogspot.com/ Java Persistence
Performance 
-- 
View this message in context: http://old.nabble.com/non-repeatable-read-in-combination-with-a-delete-tp30698828p30765851.html
Sent from the EclipseLink - Users mailing list archive at Nabble.com.



Back to the top