Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring数据JPA-并发批量插入/更新_Java_Hibernate_Spring Data_Spring Data Jpa - Fatal编程技术网

Java Spring数据JPA-并发批量插入/更新

Java Spring数据JPA-并发批量插入/更新,java,hibernate,spring-data,spring-data-jpa,Java,Hibernate,Spring Data,Spring Data Jpa,目前,我开发了一个Spring引导应用程序,它主要从消息队列(~5个并发消费者)中提取产品审查数据,并将其存储到MySQL数据库中。每个评审都可以通过其评审标识符(字符串)进行唯一标识,该标识符是主键,可以属于一个或多个产品(例如,具有不同颜色的产品)。以下是数据模型的摘录: public class ProductPlacement implements Serializable{ private static final long serialVersionUID = 1L;

目前,我开发了一个Spring引导应用程序,它主要从消息队列(~5个并发消费者)中提取产品审查数据,并将其存储到MySQL数据库中。每个评审都可以通过其评审标识符(字符串)进行唯一标识,该标识符是主键,可以属于一个或多个产品(例如,具有不同颜色的产品)。以下是数据模型的摘录:

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;
}
findByReviewIdentifier返回null时会发生什么?即使方法返回null,hibernate是否可以为可能的插入锁定reviewIdentifier


谢谢大家!

> P>从性能的角度来看,我将考虑使用以下更改来评估解决方案。

  • 从双向多主机更改为双向一主机
  • 我有一个相同的问题,从执行的DML语句中,哪一个更有效。引用

    从配置的角度来看,选项1可能更简单,但它生成的DML语句效率较低

    使用第二个选项是因为每当关联由@manytone关联控制时,DML语句总是最有效的


  • 启用DML语句的批处理
  • 启用批处理支持将减少到数据库插入/更新相同数量记录的往返次数

    引用

    hibernate.jdbc.batch_size=50
    hibernate.order\u inserts=true
    hibernate.order\u updates=true
    hibernate.jdbc.batch_version_data=true


  • 删除saveAndFlush调用的数量
  • 当前代码获取
    ProductPlacement
    ,并对每个
    review
    执行
    saveAndFlush
    ,这不会导致DML语句的批处理

    < P> >我将考虑加载<代码>产品布局>代码>实体,并将<>代码>清单Cuffer-Reals/<代码>添加到<代码> SET Cuffer-Reals/<代码>字段>代码>产品布局> /代码>实体,最后调用“代码>合并/代码>方法一次,这两个变化:

    • 使
      ProductPlacement
      实体成为关联的所有者,即通过将
      mappedBy
      属性移动到
      设置productPlacements
      实体的
      字段中
    • 通过在这些方法中使用
      reviewIdentifier
      字段,使
      CustomerReview
      实体实现
      equals
      hashCode
      方法。我相信,
      reviewIdentifier
      是唯一的,由用户指定

    最后,在使用这些更改进行性能调优时,请使用当前代码对性能进行基线测试。然后进行更改并比较这些更改是否真的导致解决方案的性能显著提高。

    要消除竞争条件,请同步
    saveAllReviews()
    或基于review键(受约束的属性)实现显式锁定。在我们的组织中,我们还需要处理这种情况。经过3年多的尝试和测试,我们找不到比按键锁定更好的方法。。。也许还有另外一种做法,我也想学习一下。谢谢你的回复。您认为同步方法和锁定密钥(性能方面)有区别吗?当然,密钥锁定会更有效,因为您可以安全地允许对不同的密钥进行并发写入。但这一方法需要实施努力。您可以先尝试
    synchronized
    ,然后在性能不满足时考虑更高级的技术。虽然这一切都提高了性能,但毫无疑问,这有助于避免并发查找-插入周期上的争用条件?@SashaSalauyou确实如此。这主要解决问题的性能方面。对于比赛条件,我倾向于同步进近,但我想知道是否有更好的方法,但目前还不确定。@Madhusudanareddysunapu感谢您的输入。我也考虑过让productPlacement成为关系的所有者,但假设一个产品有2.5k的评论。这会不会导致在集合中增加10个,从而获得2.5万条评论?是否可以将项目添加到延迟加载的集合中?@JuHarm89是的,在这种情况下会获取所有评论。如何-由于在代码中的某个点手动为新的
    Customerreview
    指定了
    reviewIdentifier
    ,因此我们可以在
    Customerreview
    中添加
    boolean isNew
    瞬态字段,该字段将根据是否是新的审阅设置为
    true/false
    。在保存上述代码中的
    reviews
    时,我们可以使用
    HQL
    new
    执行insert review并生成映射行。看起来效率更高,但也可以解决constraintViolationException。不过,一个缺点是SLC使用HQL无效。
    @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);
            }
    
        }
    }
    
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    CustomerReview findByReviewIdentifier(String reviewIdentifier);