我在Code Review论坛中提出了类似的问题,但建议在这里提出这个问题。
我想知道下面的网络方法中的synchronized
关键字。由于从线程池调用setPerson
(意味着不同的线程可以调用它),我应该以某种方式同步它。当我的客户端对方法进行SOAP调用时,EclipseLink使用thead池。我的问题是,制作网络方法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对象。我需要同步它,因此两个线程无法获得相同的主键。
答案 0 :(得分:1)
你可能会问错误的问题。同步在这里没有帮助,因为唯一有并发问题的部分是getLastInsertedId()
:您不希望两种方法获取相同的值并尝试使用该ID持久保存实例。
同步setPerson
只会解决问题,如果它是唯一可以保留Person
的方法。
如果可能,使用底层数据存储的自动递增功能;如果你的ORM解决方案没有执行上下文范围的ID分配?最后一种方法是使getNextId
的方法可以同步并返回递增的值。这最终可能会导致数据库中出现非连续的ID序列(getNextId
将不知道持久化操作是否成功),但这会减少锁定的范围。
正如JB Nizet指出的那样,ID分配需要持久化并以某种方式提供给该数据存储的所有客户端。如果您的应用程序有两个实例持久存在Person
个实例,则需要确保它们共享一个ID分配器。