How to do multithreading with embedded ObjectDB

#1

Hi,

I've tried to implement a counter with ObjectDB, but the following code doesn't work as expected:

final EntityManagerFactory emf = Persistence.createEntityManagerFactory("test.odb");
        EntityManager em = emf.createEntityManager();
        Point p = new Point(0, 0);
        em.getTransaction().begin();
        em.persist(p);
        em.getTransaction().commit();
        em.close();
        final CountDownLatch l = new CountDownLatch(100);
        for (int i = 0; i < 100; i++) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    EntityManager em = emf.createEntityManager();
                    em.getTransaction().begin();
                    //Query q = em.createQuery("UPDATE Point SET x = x + 1");
                    Query query = em.createQuery("UPDATE Point SET x = x + 1");
                    query.executeUpdate();
//                    Point p = new Point(1, 1);
//                    em.persist(p);
                    em.getTransaction().commit();
                    em.close();
                    l.countDown();
                    //To change body of implemented methods use File | Settings | File Templates.
                }
            });
            t.start();
        }
        l.await();
        em = emf.createEntityManager();
        TypedQuery<Point> myquery = em.createQuery("SELECT p from Point p", Point.class);
        List<Point> results = myquery.getResultList();
        System.out.println("X coordinate is: " + results.get(0).getX());
        em.close();

The result I expect has to be X coordinate is 100 but in reality, the code prints out different result: 2

What's wrong with my code?

 

#2

You can fix your code by one of the following ways:

1. Synchronize your update queries, so they will be executed sequently, rather than concurrently:

    synchronized (lock) {
        em.createQuery("UPDATE Point SET x = x + 1").executeUpdate();
    }

Your lock object must be one object that is shared by all the threads.

2. Use ObjectDB / JPA locking, by setting a pessimistic locking timeout, e.g. by:

        Map<String, Integer> properties =
            Collections.singletonMap("javax.persistence.lock.timeout", 1000);
        final EntityManagerFactory emf =
            Persistence.createEntityManagerFactory(
                "objectdb:$objectdb/db/test.tmp;drop", properties);

and then replacing the UPDATE query with a retrieval with a lock and an update:

        Point point = em.find(Point.class, 1, LockModeType.PESSIMISTIC_WRITE);
        point.setX(point.getX() + 1);

 

ObjectDB Support

Reply