Bug 391755 - EntityManager.lock() executes more selects than in 2.1.1 (and ignores QueryHints.REFRESH_CASCADE)
Summary: EntityManager.lock() executes more selects than in 2.1.1 (and ignores QueryHi...
Status: NEW
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P2 major (vote)
Target Milestone: ---   Edit
Assignee: Nobody - feel free to take it CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
Depends on:
Blocks:
 
Reported: 2012-10-12 06:20 EDT by Ronny Völker CLA
Modified: 2022-06-09 10:23 EDT (History)
2 users (show)

See Also:


Attachments
test case (29.34 KB, application/octet-stream)
2013-02-08 04:51 EST, Ronny Völker CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ronny Völker CLA 2012-10-12 06:20:05 EDT
My code contains an entity with four associations (all lazy). It is used in the following call sequence:

Entity e = new Entity(); // all associations are initialized with empty collections.
em.getTransaction().begin();
em.persist(e);
em.getTransaction().commit();
em.lock( e, LockModeType.PESSIMISTIC_WRITE);
...

In v2.1.1 em.lock() caused one select for update.
In v2.4 it causes four more selects - one for each association.
This is a problem for me, because in this part of the code performance is critical.

It looks like when calling lock(e) in 2.4 not only e is refreshed, but also all of the associations of e. It would be sufficient for me to just refresh e.

Adding the QueryHint REFRESH_CASCADE=CascadePolicy.NoCascading to the call of em.lock() doesn't change anything.
Comment 1 Ronny Völker CLA 2012-10-12 06:44:36 EDT
It looks like ForeignReferenceMapping.buildCloneFromRow()together with ForeignReferenceMapping.valueFromRowInternal() are causing the additional selects.

For each association ForeignReferenceMapping.valueFromRowInternal() returns a new IndirectList. ForeignReferenceMapping.buildCloneFromRow() later calls indirectionPolicy.instantiateObject() on the IndirectList which causes the additional select.

From my point of view, at least with QueryHint.REFRESH_CASCADE=CascadePolicy.NoCascading, the methods should just clone the existing collection for each association, instead of replacing it with a new IndirectList(which is right after that loaded from the db).
Comment 2 Tom Ware CLA 2012-11-16 13:28:20 EST
Setting target and priority.  See the following page for the meanings of these fields:

http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines

Community: Please vote for this bug if it is important to you.  Votes are one of the main criteria we use to determine which bugs to fix next.
Comment 3 James Sutherland CLA 2013-01-17 10:27:41 EST
This behavior has not changed.

Cascade means refresh the related objects, the relationships of the source object must always be rebuilt from the row.

If they are not refreshed then your lock will not prevent concurrent changes to these relationships.
Comment 4 Ronny Völker CLA 2013-02-08 04:51:47 EST
Created attachment 226750 [details]
test case

Added test case:

@Entity
public class A
{      
  @OneToMany( mappedBy = "a")
  public Set<B> bs = new HashSet< B >();
...

@Entity
public class B
{    
  @ManyToOne
  public A a;
...
      A a = new A();
      em.getTransaction().begin();
      em.persist( a );
      em.getTransaction().commit();
      em.getTransaction().begin();
      em.lock( a, LockModeType.PESSIMISTIC_WRITE );
      //causes in 2.1.1:
      //  SELECT ID FROM A WHERE (ID = :1) FOR UPDATE
      //causes in 2.4:
      //  SELECT ID FROM A WHERE (ID = :1) FOR UPDATE
      //  SELECT ID, A_ID FROM B WHERE (A_ID = :1)
      ...

The behaviour of 2.1.1 is ok for me, because I don't mind if the Bs are changed concurrently. In fact I know, that the Bs won't change concurrently.

Interestingly there is a similar scenario where 2.4 behaves the same way as 2.1.1, which seems at least a bit inconsistent to me:

      A a = new A();
      em.getTransaction().begin();
      em.persist( a );
      em.getTransaction().commit();
      id = a.id;
      ...get new EntityManager...
      A a = em.find( A.class, id );
      em.getTransaction().begin();
      em.lock( a, LockModeType.PESSIMISTIC_WRITE );
      //causes in 2.1.1, as well as in 2.4:
      //  SELECT ID FROM A WHERE (ID = :1) FOR UPDATE
      ...

.hg/patches contains a patch, to switch the test case from 2.1.1 to 2.4.
Comment 5 Eclipse Webmaster CLA 2022-06-09 10:23:55 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink