目前我开发了一个Spring Boot应用程序,它主要从消息队列(~5并发消费者)中提取产品评论数据并将它们存储到MySQL DB中。每个评论可以通过其reviewIdentifier(字符串)唯一地标识,该标识符是主键并且可以属于一个或多个产品(例如,具有不同颜色的产品)。以下是数据模型的摘录:
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。现在我想要一种有效的方法来坚持产品的评论。每次进入审查都需要考虑两个案例:
目前我的持久评论方法不是最佳方法。它看起来如下(使用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);
}
}
}
问题:
更新问题1:我的Review-Repository上的简单@Lock会不会出现唯一约束异常?
@Lock(LockModeType.PESSIMISTIC_WRITE)
CustomerReview findByReviewIdentifier(String reviewIdentifier);
当findByReviewIdentifier返回null时会发生什么?即使方法返回null,hibernate是否可以锁定reviewIdentifier以查找可能的插入?
谢谢!
答案 0 :(得分:4)
从性能的角度来看,我会考虑通过以下更改来评估解决方案。
我对从执行的DML语句中哪一个更有效率有一个相同的问题。引自Typical ManyToMany mapping versus two OneToMany。
从配置角度来看,选项一可能更简单,但它会产生效率较低的DML语句。
使用第二个选项,因为每当关联由@ManyToOne关联控制时,DML语句总是最有效的。
启用批处理支持将导致数据库往返次数减少,以插入/更新相同数量的记录。
引自batch INSERT and UPDATE statements
hibernate.jdbc.batch_size = 50
hibernate.order_inserts = true
hibernate.order_updates = true
hibernate.jdbc.batch_versioned_data = true
当前代码获取ProductPlacement
,并且对于每个review
,它执行saveAndFlush
,这导致不批处理DML语句。
相反,我会考虑加载ProductPlacement
实体并将List<CustomerReview> customerReviews
添加到Set<CustomerReview> customerReviews
实体的ProductPlacement
字段,最后调用merge
方法一次最后,有了这两个变化:
ProductPlacement
实体所有者,即将mappedBy
属性移至Set<ProductPlacement> productPlacements
实体的CustomerReview
字段。CustomerReview
字段使equals
实体实现hashCode
和reviewIdentifier
方法。我相信reviewIdentifier
是唯一且用户已分配。最后,当您使用这些更改进行性能调整时,请使用当前代码确定性能基准。然后进行更改并比较更改是否真正导致解决方案的任何显着性能改进。