我需要在ObjectDB中拥有一个原子计数器,但是以下代码无法按预期工作:

    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();
                em.getTransaction().commit();
                em.close();
                l.countDown();
            }
        });
        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 coordiate is: " + results.get(0).getX());
    em.close();


它应该已经打印出X坐标为100。但是实际上,不是。

我的代码有什么问题?

最佳答案

您可以通过以下方式之一来修复代码:

同步您的更新查询,以便它们将顺序执行,而不是同时执行:

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


您的锁对象必须是所有线程共享的一个对象。

或者,通过设置悲观的锁定超时来使用ObjectDB / JPA锁定,例如通过:

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


然后用带有锁和更新的检索替换UPDATE查询:

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

关于java - 嵌入式ObjectDB的多线程,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23213969/

10-09 00:10