【发布时间】:2016-07-21 06:27:00
【问题描述】:
目前我开发了一个 Spring Boot 应用程序,它主要从消息队列(约 5 个并发消费者)中提取产品评论数据并将它们存储到 MySQL 数据库中。每条评论都可以通过它的 reviewIdentifier (String) 唯一标识,它是主键,可以属于一个或多个产品(例如不同颜色的产品)。以下是数据模型的摘录:
public class ProductPlacement implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "product_placement_id")
private long id;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="productPlacements")
private Set<CustomerReview> customerReviews;
}
public class CustomerReview implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "customer_review_id")
private String reviewIdentifier;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(
name = "tb_miner_review_to_product",
joinColumns = @JoinColumn(name = "customer_review_id"),
inverseJoinColumns = @JoinColumn(name = "product_placement_id")
)
private Set<ProductPlacement> productPlacements;
}
队列中的一条消息包含 1 到 15 条评论和一个 productPlacementId。现在我想要一种有效的方法来保留产品的评论。每次收到的评论基本上有两种情况需要考虑:
- 评论不在数据库中 -> 参考消息中包含的产品插入评论
- 评论已在数据库中 -> 只需将产品引用添加到现有评论的 Set productPlacements 即可。
目前,我保留评论的方法不是最佳的。它看起来如下(使用 Spring Data JpaRespoitories):
@Override
@Transactional
public void saveAllReviews(List<CustomerReview> customerReviews, long productPlacementId) {
ProductPlacement placement = productPlacementRepository.findOne(productPlacementId);
for(CustomerReview review: customerReviews){
CustomerReview cr = customerReviewRepository.findOne(review.getReviewIdentifier());
if (cr!=null){
cr.getProductPlacements().add(placement);
customerReviewRepository.saveAndFlush(cr);
}
else{
Set<ProductPlacement> productPlacements = new HashSet<>();
productPlacements.add(placement);
review.setProductPlacements(productPlacements);
cr = review;
customerReviewRepository.saveAndFlush(cr);
}
}
}
问题:
- 我有时会因为违反“reviewIndentifier”上的唯一约束而得到 constraintViolationExceptions。这显然是因为我(同时)查看评论是否已经存在,然后插入或更新它。我怎样才能避免这种情况?
- 在我的情况下使用 save() 还是 saveAndFlush() 更好。我每秒收到约 50-80 条评论。如果我只使用 save() 会自动刷新休眠还是会导致内存使用量大大增加?
对问题 1 的更新:我的 Review-Repository 上的简单 @Lock 会防止出现唯一约束异常吗?
@Lock(LockModeType.PESSIMISTIC_WRITE)
CustomerReview findByReviewIdentifier(String reviewIdentifier);
当 findByReviewIdentifier 返回 null 时会发生什么?即使方法返回 null,hibernate 是否可以锁定可能插入的 reviewIdentifier?
谢谢!
【问题讨论】:
-
要摆脱竞争条件,要么使
saveAllReviews()同步,要么根据审查的键(受约束的属性)实施显式锁定。在我们的组织中,我们也需要处理这种情况。经过 3 年多的尝试和测试,我们找不到比按键锁定更好的方法……也许还有另一种做法,我也想学习它。 -
感谢您的回复。您是否认为使方法同步和锁定密钥(性能方面)有区别
-
当然键锁定会更有效,因为您可以安全地允许不同键的并发写入。但这种方法需要实施工作。您可以先尝试
synchronized,如果性能不满意,再考虑更高级的技术。
标签: java hibernate spring-data spring-data-jpa