1092 words

Remove an entity which attributes were changed - OptimisticLockException

#1
2016-04-14 13:06

We use an OSGi environment and we have three OSGi plugins.

 

In plugin A an entity is loaded and the entity is passed to plugin B.

Plugin B changes an attribute on the entity.

Plugin C removes the entity from the database.

After commit the transaction an exception is caused with optimistic lock exception of the removed entity.

If this operations on the entity are executed in only one plugin, it works well.

Why the ObjectDB want to commit the changes of the entity although the entity will be removed, if we use three OSGi plugins.

btc_es
btc_es's picture
Joined on 2014-10-20
User Post #116
#2
2016-04-14 13:08

The difference between using one plugin or several plugins seems to be using one or more EntityManagerFactory / EntityManager instances, i.e. this could also be demonstrated by a non OSGi application:

  • User 1 retrieves an object and changes it.
  • User 2 retrieves an object, removes it and commit.

This should work if the changes of user 1 are local in memory and will fail with OptimisticLockException if user 1 is committing or flushing the changes before user 2 is trying to remove the object, since then there is a conflict between two different operations on the same object by two different users.

Note that user 1 may flush the changes implicitly by running a query. You can run specific queries with COMMIT flush mode to avoid flushing changes to the database.

You may also disable optimistic locking checks if you do not need it.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #2,489
#3
2016-04-14 14:31

We use only one entity manager, one transaction and one thread.

The problem is not the wrong practice of operations. The ObjectDB does not throw the changes of the entity, if entity will remove. And this is only the case, if invoking the operations in different plugins. This leads to the optimistic lock exception.

But the ObjectDB throws the changes of the entity, if invoking the operations in one plugin.

In both cases the operations are the same. What is the reason why the ObjectDB can not avoid the invoking of the changes although the entity will remove?

btc_es
btc_es's picture
Joined on 2014-10-20
User Post #117
#4
2016-04-14 16:10

What do you mean by "ObjectDB throws the changes of the entity"?

Are you sure that the same EntityManager (not just the same EntityManagerFactory) is used by the different plugins?

Could you please check if the same Java instance is used by the two operations (as should be when only one EntityManager is used) or different Java instances?

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #2,490
#5
2016-04-15 12:56

I meant the ObjectDB throws away the changes of entity, because it is not necessary to commit the changes, if the entity will be removed. This happens, if used in one plugin, but is not happen, if used in several plugins.

We use really one EntityManager in all plugins.
And also the entity instances in both plugins are identical.
I checked all of this with a debugger.

 

We had a similar issue last year 2015-11-09 under the forum task 'Remove a modified entity cause an optimistic lock exception'. Maybe it helps to pin down the source of the issue.

btc_es
btc_es's picture
Joined on 2014-10-20
User Post #118
#6
2016-04-15 14:37

Forum thread "Remove a modified entity cause an optimistic lock exception" indeed discusses a similar problem. However, the test case on that forum thread still passes with the last ObjectDB version.

ObjectDB maintains a version number for every entity object, which is increased on every update. An OptimisticLockException is thrown when that version number indicates a concurrent update by another user (using another EntityManager). According to your description this is not the case.

In order to understand the cause, please track the object version. You can do that easily by adding a version field to the entity class, so the version number will be injected to that field.

Please check this version number during the operations with one plugin and with multiple plugins and find the exact point of difference between these two modes.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #2,491
#7
2016-04-15 15:05

I have found the problem.

Our entity had the version = 3 on entityA (Type A) and after a find operation on another entityB (Type B) the version changed to 8.

entityA.setMap(); // change the entity field

EntityManager em = getEntityManager();
entityB = em.find(TypeB, uid of TypeB);

I don't understand why this operation leads to increase the version number of entity, although both entities haven't any relation each other.

This fails also in both cases, with several plugins and with one plugin.

btc_es
btc_es's picture
Joined on 2014-10-20
User Post #119
#8
2016-04-15 16:32

This is definitely an unexpected behaviour.

If it fails also with one plugin, could you try isolating it further to a simple test console application?

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #2,492
#9
2016-05-14 16:52

In a simple console application the issue is not occurred.

I created an OSGi example for eclipse mars, with plugins com.btc.ep.base.dal.tests.it and main.You can execute the unit test OptimisticLockTest as a JUnit Plugin Test. The test causes the optimistic lock exception.


 

 

btc_es
btc_es's picture
Joined on 2014-10-20
User Post #121
#10
2016-05-15 07:59

The test fails with another exception:

java.lang.NullPointerException
at org.osgi.util.tracker.ServiceTracker.<init>(ServiceTracker.java:184)
at com.btc.ep.core.Services.getServiceTracker(Services.java:23)
at com.btc.ep.core.Services.get(Services.java:34)
at com.btc.ep.base.dal.tests.it.OptimisticLockTest.getPersistenceService2(OptimisticLockTest.java:97)
at com.btc.ep.base.dal.tests.it.OptimisticLockTest.deleteDatabase(OptimisticLockTest.java:92)
at com.btc.ep.base.dal.tests.it.OptimisticLockTest.setUp(OptimisticLockTest.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #2,507
#11
2016-05-16 19:05

Please execute the unit test OptimisticLockTest as a JUnit Plugin Test.

btc_es
btc_es's picture
Joined on 2014-10-20
User Post #122
#12
2016-05-23 11:56

The issue can be demonstrated by the following test case:

import javax.persistence.*;
 
public class F1056 {
 
    public static void main(String[] args) {
 
        EntityManagerFactory emf =
            Persistence.createEntityManagerFactory(
                "objectdb:$objectdb/db/test.tmp;drop");
 
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        em.persist(new MyEntity());
        em.getTransaction().commit();
        em.close();
 
        em = emf.createEntityManager();
        em.getTransaction().begin();
        MyEntity e = em.find(MyEntity.class, 1);
        e.value++;
        em.flush();
        em.remove(e);
        em.flush();
        em.getTransaction().commit();
        em.close();
 
        emf.close();
    }
 
    @Entity
    public static class MyEntity {
        @Id @GeneratedValue long id;
        int value;
    }
}

Version 2.6.8 fixes the bug.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #2,508
#13
2016-05-31 12:11

The fix solves the issue.

But now we have another issue in our OSGi Test (use eclipse mars) with plugins com.btc.ep.base.dal.tests.it and main.

You can execute the unit test RemovedFormalRequirementIsAlwaysInTheDatabaseTest as a JUnit Plugin Test.

The test shows an FormalRequirementImpl entity which the test has removed. But in another transaction the FormalRequirementImpl exists in the database yet.

We had expected an exception that the entity could not be removed.

See the attachment.

 

btc_es
btc_es's picture
Joined on 2014-10-20
User Post #124
#14
2016-05-31 13:42

Could you please demonstrate the issue with a simple example, as in #12 above? Maybe by applying a small change to that console test case? It is very difficult to follow an issue in a large test case (2 projects, 46 java files, which most of it is unrelated to the reported issue).

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #2,510
#15
2016-05-31 14:17

Yes - you can directly use your Test-Example.

Check the Database after removing Object 'e'

 

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;
 
public class F1056 {
public static void main(String[] args) {
 
        EntityManagerFactory emf =
            Persistence.createEntityManagerFactory(
                "objectdb:$objectdb/db/test.tmp;drop");
 
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        MyEntity entity = new MyEntity();
        em.persist(entity);
        em.getTransaction().commit();
        em.close();
 
        em = emf.createEntityManager();
        em.getTransaction().begin();
        MyEntity e = em.find(MyEntity.class, 1);
        e.value++;
        em.flush();
 
        long removedID = e.id;
        em.remove(e); // remove e
        em.flush();
        em.getTransaction().commit();
        em.close();
 
        em = emf.createEntityManager();
        em.getTransaction().begin();
        MyEntity removed = em.find(MyEntity.class, removedID);
        if (removed != null) {
            System.out.println("Find removed Entity... " + removed);
            throw new RuntimeException();
        }
        em.getTransaction().commit();
        em.close();
 
        emf.close();
    }
 
    @Entity
    public static class MyEntity {
        @Id
        @GeneratedValue
        long id;
        int value;
    }
}

 

btc_es
btc_es's picture
Joined on 2014-10-20
User Post #125
#16
2016-05-31 18:14

Thanks. Build 2.8.0_01 should fix it.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #2,512
#17
2016-06-01 15:05

Thanks. The issue is solved with Build 2.8.0_01.

btc_es
btc_es's picture
Joined on 2014-10-20
User Post #126

Post Reply

Please read carefully the posting instructions - before posting to the ObjectDB website.

  • You may have to disable pop up blocking in order to use the toolbar (e.g. in Chrome).
  • Use ctrl + right click to open the browser context menu in the editing area (e.g. for using a browser spell checker).
  • To insert formatted lines (e.g. Java code, stack trace) - select a style in the toolbar and then insert the text in the new created block.
  • Avoid overflow of published source code examples by breaking long lines.
  • You may mark in paragraph code words (e.g. class names) with the code style (can be applied by ctrl + D).
  • Long stack traces (> 50 lines) and complex source examples (> 100 lines) should be posted as attachments.
Attachments:
Maximum file size: 32 MB
Cancel