gpt4 book ai didi

java - 实体管理器获取或创建

转载 作者:行者123 更新时间:2023-11-29 07:28:14 25 4
gpt4 key购买 nike

我如何确定对象是否已经存在而不是再次创建。

@Component
public class ProductServiceImpl implements ProductService
{
@PersistenceContext
private EntityManager em;

public Product getOrCreateProduct(String productName, String peoductDescr)
{
Product product =(new Product (productName, peoductDescr));
em.merge(product);
return product;
}
}

我这样做了,但因为它仍然继续创建新的数据库条目而不是返回新的。

最佳答案

虽然 John 的回答在大多数情况下都有效,但存在一个多线程问题,如果两个线程同时调用 getOrCreateProduct,这可能会导致一次调用失败。如果没有,两个线程都可能会尝试查找现有产品并进入 NoResultException block 。然后两者都会创建一个新产品并尝试合并它。在 transaction.commit() 上,只有一个线程会成功,另一个线程将进入 PersistenceException block 。

这可以通过可选地使用双重检查锁定来同步您的方法(对性能有影响)来处理,或者因为您已经在使用 spring,您可以使用 spring 的 @Retryable 功能。

以下是不同方式的示例。所有的方法都是线程安全的并且可以工作。但在性能方面,getOrCreateProductWithSynchronization 将是最差的,因为它会同步每个调用。 getOrCreateProductWithDoubleCheckedLockinggetOrCreateProductWithRetryable 从性能角度来看应该几乎相同。也就是说,您必须决定是使用双重检查锁定引入的额外代码复杂性,还是使用仅限 spring 的 @Retryable 功能。

@Transactional(propagation = Propagation.REQUIRES_NEW)
public synchronized Product getOrCreateProductWithSynchronization(final String productName, final String productDescr) {

Product product = findProduct(productName);
if (product != null) {
return product;
}

product = new Product(productName, productDescr);
em.persist(product);

return product;
}


@Transactional(propagation = Propagation.REQUIRES_NEW)
public Product getOrCreateProductWithDoubleCheckedLocking(final String productName, final String productDescr) {

Product product = findProduct(productName);
if (product != null) {
return product;
}

synchronized (this) {
product = findProduct(productName);
if (product != null) {
return product;
}

product = new Product(productName, productDescr);
em.persist(product);
}

return product;
}


@Retryable(include = DataIntegrityViolationException.class, maxAttempts = 2)
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Product getOrCreateProductWithRetryable(final String productName, final String productDescr) {

Product product = findProduct(productName);
if (product != null) {
return product;
}

product = new Product(productName, productDescr);
em.persist(product);
return product;
}


private Product findProduct(final String productName) {
// try to find an existing product by name or return null
}

更新:还有一件事要注意。如果您只有一个服务实例,则使用 synchronized 的实现只会正常工作。也就是说,在分布式设置中,如果在您的服务的两个或多个实例上并行调用,这些方法仍然可能会失败。 @Retryable 解决方案也能正确处理这个问题,因此应该是首选解决方案。

关于java - 实体管理器获取或创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47274119/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com