Spring Data JPA与批处理保存的性能问题



我有以下实体

@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();
}
}

使用以下代码将记录插入app_item表

@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

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

有人能告诉我,如何提高以上JPA代码的性能吗。我们正在使用hibernate来实现jpa。

为了提高插入的性能,您应该使用自定义代码实现批量插入。下面的方法将确保批次被刷新到数据库中。根据性能测试调整批量大小。一般来说,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();
}
}
}

以上更改将创建多个插入语句。您可以通过设置hibernate配置来进一步优化插入查询。

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

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

最新更新