0

我在 Code Review 论坛上问了一个类似的问题,但有人建议在这里问这个问题。我想知道synchronized下面的网络方法中的关键字。由于setPerson是从线程池调用的(意味着不同的线程可以调用它),我应该以某种方式同步它。当我的客户端对该方法进行 SOAP 调用时,EclipseLink 会使用 thead 池。我的问题是,制作 web 方法是否是一种好习惯,synchronized或者我可以与之同步em.lock(person, WRITE)吗?

@Override
public synchronized void setPerson(Person person) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersonLibPU");            
    EntityManager em = emf.createEntityManager(); 
    if(!em.getTransaction().isActive()) {
       em.getTransaction().begin();
    }
    try {
         person.setPersonId(getLastInsertedId() + 1); // Get the last inserted ID and increment it by 1
         em.merge(person);
         em.getTransaction().commit();  
         emf.getCache().evict(Person.class);                    
    } catch (Exception ex) {
         if(em.getTransaction().isActive())
            em.getTransaction().rollback();
    } finally {
        em.close();
    }
}

编辑
我在上面的代码中添加了一行,在其中设置了 person 对象的主键值。这就是同步的目的,而不是任何共享的 java 对象。我需要同步它,这样两个线程就无法获得相同的主键。

4

1 回答 1

1

你可能问错了问题。同步在这里对您没有帮助,因为唯一存在并发问题的部分是getLastInsertedId():您不希望两个方法获取相同的值并尝试使用该 ID 持久化一个实例。

同步setPerson只有在它是唯一持续存在的方法时才能解决问题Person

如果可能,请使用底层数据存储的自动递增功能;如果失败了,您的 ORM 解决方案是否会执行上下文范围的 ID 分配?最后的手段是有一个可以同步的方法getNextId返回一个递增的值。这可能会导致数据库中的 ID 序列不连续(getNextId不知道持久化操作是否成功),但这会减少锁定的范围。

正如 JB Nizet 指出的那样,ID 分配需要持久化,并以某种方式提供给该数据存储的所有客户端。如果您的应用程序有两个实例持久化Person实例,则需要确保它们共享一个 ID 分配器。

于 2012-06-25T08:12:21.650 回答