本文介绍了Spring Data JPA执行无法批量保存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下实体

  @Entity 
@Table(name =APP_ITEM)
public class AppItem实现Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
私人AppItemPK AppItemPK;

public AppItemPK getAppItemPK(){
return appItemPK;
}

public void setAppItemPK(
AppItemPK appItemPK){
this.appItemPK = appItemPK;



$ b @Embeddable
public class AppItemPK实现Serializable {

private static final long serialVersionUID = 1L;
@Column(name =app_id)
private long appId;
@Column(name =item_id)
private long itemId;

public Long getAppId(){
return appId;
}

public void setAppId(Long appId){
this.appId = appId;
}

public Long getItemId(){
return itemId;
}

public void setItemId(Long itemId){
this.itemId = itemId;

$ b $ public boolean equals(Object obj){
if(obj instanceof AppItemPK){
AppItemPK appItemPK =(AppItemPK)obj;
if(appItemPK.getItemId()。equals(this.itemId)
&& appItemPK.getAppId()。equals(
this.appId)){
return true ;
}
}
返回false;


public int hashCode(){
return this.itemId.hashCode()+ this.applicationId.hashCode();
}

}

使用下面的代码将记录插入app_item table



pre $ @Transactional(readOnly = false)
public boolean saveItemSelection(PageHeaderViewData pageHeaderViewData,Map< Long,Boolean> selectedItems,String savedItems){
long millisSaveStart = Calendar.getInstance()。getTimeInMillis();
log.debug(Inside saveItemSelection appId:+ pageHeaderData.getAppId());
布尔saveStatus = false;
列表< AppItem> appItemInsList = new ArrayList< SavedApplicationItem>(); (Entry< Long,Boolean> idEntry:selectedItems.entrySet()){
if(pageHeaderData.getAppId()!= null){

if (idEntry!= null){

if(idEntry.getValue()&&!savedItems.contains(idEntry.getKey()。toString())){
// log .debug(SaveItemSelection SAVED itemId:+ idEntry.getKey()+,Value:+ idEntry.getValue());
AppItem appItem = new AppItem();
AppItemPK appItemPK = new AppItemPK();
appItemPK.setAppId(pageHeaderData.getAppId());
appItemPK.setItemId(idEntry.getKey());
appItem.setAppItemPK(appItemPK);
appItem.setUpdateInd(ToggleEnum.Y);
appItemInsList.add(appItem);
//appItemRepository.saveAndFlush(appItem);







$ if(appItemInsList.size()!= 0 ){
long millisJPASaveStart = Calendar.getInstance()。getTimeInMillis();
appItemRepository.save(appItemInsList);
long millisJPASaveEnd = Calendar.getInstance()。getTimeInMillis();
log.debug(JPA save time:+(millisJPASaveEnd-millisJPASaveStart));
}

saveStatus = true;

long millisSaveEnd = Calendar.getInstance()。getTimeInMillis();
log.debug(Total Save time:+(millisSaveEnd-millisSaveStart));
}

return saveStatus;

} // saveItemSelection结束

要插入5000条记录, 13826毫秒。

有人可以告诉我,如何提高上述JPA代码的性能。我们使用hibernate来实现jp​​a。

解决方案

为了提高插入性能,您应该使用自定义代码实现批量插入。下面的方法将确保将批次刷新到数据库。根据您的性能测试调整批量大小。一般来说50是一个很好的开始。

  @Transactional 
public void bulkPersist(List< Entity> entities){
int i = 0;
for(Entity entity:entities){
em.persist(entity);
i ++;

if(i%batchSize == 0){
flush();
clear();





$ p $上面的变化将创建多个插入声明。您可以通过设置hibernate配置来进一步优化插入查询。

 < prop key =hibernate.order_inserts>真LT; /丙> 
< prop key =hibernate.order_updates> true< / prop>

提示:启用调试日志以查看每个批次正在生成1个插入查询。

b $ b

I have the following Entity

@Entity
@Table(name = "APP_ITEM")
public class AppItem implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private AppItemPK AppItemPK;

 public AppItemPK getAppItemPK() {
    return appItemPK;
}

public void setAppItemPK(
        AppItemPK appItemPK) {
    this.appItemPK = appItemPK;
}
}


@Embeddable
public class AppItemPK implements Serializable {

private static final long serialVersionUID = 1L;
@Column(name = "app_id")
private Long appId;
@Column(name = "item_id")
private Long itemId;

public Long getAppId() {
    return appId;
}

public void setAppId(Long appId) {
    this.appId = appId;
}

public Long getItemId() {
    return itemId;
}

public void setItemId(Long itemId) {
    this.itemId = itemId;
}

public boolean equals(Object obj) {
    if (obj instanceof AppItemPK) {
        AppItemPK appItemPK = (AppItemPK) obj;
        if (appItemPK.getItemId().equals(this.itemId)
                && appItemPK.getAppId().equals(
                        this.appId)) {
            return true;
        }
    }
    return false;
}

public int hashCode() {
    return this.itemId.hashCode() + this.applicationId.hashCode();
}

}

Using below code to insert record into app_item table

@Transactional(readOnly = false)
public boolean saveItemSelection(PageHeaderViewData pageHeaderViewData, Map<Long, Boolean> selectedItems,String savedItems){
    long millisSaveStart = Calendar.getInstance().getTimeInMillis();
    log.debug("Inside saveItemSelection appId:"+pageHeaderData.getAppId());
    boolean saveStatus = false;
    List<AppItem> appItemInsList = new ArrayList<SavedApplicationItem>();

    if (pageHeaderData.getAppId() != null) {

         for (Entry<Long, Boolean> idEntry : selectedItems.entrySet() ) {
             if (idEntry!= null){

                     if (idEntry.getValue() && !savedItems.contains(idEntry.getKey().toString())){
                         //log.debug("Inside saveItemSelection SAVED itemId:"+idEntry.getKey()+" , Value:"+idEntry.getValue());
                         AppItem appItem = new AppItem();
                         AppItemPK appItemPK = new AppItemPK();
                         appItemPK.setAppId(pageHeaderData.getAppId());
                         appItemPK.setItemId(idEntry.getKey());
                         appItem.setAppItemPK(appItemPK);
                         appItem.setUpdateInd(ToggleEnum.Y);
                         appItemInsList.add(appItem);
                         //appItemRepository.saveAndFlush(appItem);
                     }
                 }
             }


         }


         if (appItemInsList.size() != 0){
             long millisJPASaveStart = Calendar.getInstance().getTimeInMillis();
             appItemRepository.save(appItemInsList);
             long millisJPASaveEnd = Calendar.getInstance().getTimeInMillis();
             log.debug("JPA save time:"+(millisJPASaveEnd-millisJPASaveStart));
         }

         saveStatus = true;

         long millisSaveEnd = Calendar.getInstance().getTimeInMillis();
         log.debug("Total save time:"+(millisSaveEnd-millisSaveStart));
    }

    return saveStatus;

}//end of saveItemSelection

For inserting 5000 records it is taking 13826 milliseconds.

Can someone please let me know, how to improve the performance in above JPA code. We are using hibernate for jpa implementation.

解决方案

To improve the performance your inserts, you should implement batch insert using custom code. The method below will make sure that batches are flushed to the database. Tweak the batch size based on your performance tests. Generally 50 is a good number to start.

@Transactional
public void bulkPersist(List<Entity> entities) {
  int i = 0;
  for (Entity entity : entities) {
    em.persist(entity);
    i++;

    if (i % batchSize == 0) {
      flush();
      clear();
    }
  }
}

Above change will create multiple insert statements. You can further optimize the insert query by setting up the hibernate configuration.

<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.order_updates">true</prop>

Tip: Enable Debug log to see 1 insert query is being generated per batch.

这篇关于Spring Data JPA执行无法批量保存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 17:58