在实际应用中,使用Hibernatez作为持久化框架,处理更新实体时,有一些潜在的效率问题。
1、场景:
实体表包含多个字段,或者字段中存在blob或clob大字段,同时,可能这些实体有缓存支持,这样在事务中难以操作和实现部分更新。
如:一个模板实体Template中:
@Entity
@Table(name = "TASKTEMPLATE")
// @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@TypeDefs({ @TypeDef(name = "blob", typeClass = BlobByteArrayType.class) })
public class TaskTemplate implements Serializable {
private static final long serialVersionUID = 1L;
public TaskTemplate() {
}
public TaskTemplate(String id, byte[] wordContent) {
this.id = id;
this.wordContent = wordContent;
}
@Id
@Column(name = "sid", length = 32)
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid.hex")
private String id;
@Type(type = "blob")
@Column(length = 20971520)
private byte[] excelContent;
// 任务包内容
@Type(type = "blob")
@Column(length = 20971520)
private byte[] zipContent;
// 模型信息
@Type(type = "blob")
@Column(length = 20971520)
private byte[] xmlContent;
@Type(type = "blob")
@Column(length = 20971520)
private byte[] wordContent;// Word模板
@ManyToOne
@Index(name = "TASK_TEMPLATE_IDX")
@JoinColumn(name = "TASK_ID")
private Task task;
/**
* 列表展示图片(24的)
*/
@Type(type = "blob")
@Column(length = 20971520)
private byte[] images;
/**
* 平铺展示图片(48的)
*/
@Type(type = "blob")
@Column(length = 20971520)
private byte[] imagesTile;
public byte[] getImagesTile() {
return imagesTile;
}
public void setImagesTile(byte[] imagesTile) {
this.imagesTile = imagesTile;
}
public byte[] getImages() {
return images;
}
public void setImages(byte[] images) {
this.images = images;
}
public Task getTask() {
return task;
}
public void setTask(Task task) {
this.task = task;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public byte[] getExcelContent() {
return excelContent;
}
public void setExcelContent(byte[] excelContent) {
this.excelContent = excelContent;
}
public byte[] getZipContent() {
return zipContent;
}
public void setZipContent(byte[] zipContent) {
this.zipContent = zipContent;
}
public byte[] getXmlContent() {
return xmlContent;
}
public void setXmlContent(byte[] xmlContent) {
this.xmlContent = xmlContent;
}
public byte[] getWordContent() {
return wordContent;
}
public void setWordContent(byte[] wordContent) {
this.wordContent = wordContent;
}
}
这么多的大字段,在处理类似的更新时可能存在这种写法:
List<TaskTemplate> taskTemplates = taskTemplateManager.getByTaskID(tsk.getId());
for (TaskTemplate taskTemplate : taskTemplates) {
if (imageForm != null)
taskTemplate.setImages(imageForm);
if (imageTile != null)
taskTemplate.setImagesTile(imageTile);
}
taskTemplateManager.saveOrUpdateAll(taskTemplates);
2、处理:并且这里的saveOrUpdateAll使用时Hibernate中模板类方式,更新将会是全表的所有字段。但实际上应用只有来两个需要变化的字段,处理就可以改为这样比较合适:(1、使用hql限制字段 2、使用软解析赋值处理)
public void saveAndUpdateLittle(TaskTemplate taskTemplates){
String update = "update TaskTemplate t set t.images=?,t.imagesTile=? where t.id = ?";
taskTemplateDao.executeHql(update, taskTemplates.getImages(),taskTemplates.getImagesTile(),taskTemplates.getId());
}
public void executeHql(String hsql,Object... values) throws HibernateException{
Query query = createQuery(hsql, values);
query.executeUpdate();
}
public Query createQuery(final String hql,
final Object... values) {
return (Query) this.getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
Query query = session.createQuery(hql);
if (values != null) {
for (int i = 0; i < values.length; i++) {
query.setParameter(i, values[i]);
}
}
return query;
}
});
}
这样,问题解决了,并且效率得到较大提升: