hibernate 普通欄位延遲載入無效的解決辦法(如:Lazy Fetch Blob)
http://blog.csdn.net/dys1990/article/details/38728175
http://stackoverflow.com/questions/2605477/spring-hibernate-blob-lazy-loading
關於普通欄位的延遲載入,尤其是lob欄位,若沒有延遲載入,對效能影響極大。然而簡單的使用 @Basic(fetch = FetchType.LAZY) 註解並沒有效果。hibernate對此的解釋是Lazy property loading requires buildtime bytecode instrumentation. If your persistent classes are not enhanced, Hibernate will ignore lazy property settings and return to immediate fetching.
正是因為我們的persistent classes沒有使用bytecode instrumentation增強,才導致了普通欄位無法延遲載入。
因此要改寫一下。以下為一個使用了bytecode instrumentation的持久類:
關鍵在於FieldHandled介面和lob欄位的getter
public class PublicSchemeTaskFile implements java.io.Serializable , FieldHandled { // Fields /** * */ private static final long serialVersionUID = -8297912895820802249L; private Integer id; private PublicTask publicSchemeTask; private Integer fileType; private String fileName; private byte[] content; private FieldHandler fieldHandler;//用於延遲載入表字段,關聯物件延遲載入的話無需此技術 @JSON(serialize = false) public FieldHandler getFieldHandler() { return fieldHandler; } public void setFieldHandler(FieldHandler fieldHandler) { this.fieldHandler = fieldHandler; } // Constructors /** default constructor */ public PublicSchemeTaskFile() { } /** minimal constructor */ public PublicSchemeTaskFile(Integer id) { this.id = id; } // Property accessors @Id @Column(name="ID", unique=true, nullable=false, precision=22, scale=0) @GeneratedValue(strategy=GenerationType.SEQUENCE,generator = "PUBLIC_SCHEME_TASK_FILE_SEQ") public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } @JSON(serialize = false) @ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name="PUBLIC_TASK_ID") public PublicTask getPublicSchemeTask() { return this.publicSchemeTask; } public void setPublicSchemeTask(PublicTask publicSchemeTask) { this.publicSchemeTask = publicSchemeTask; } @Column(name="FILE_TYPE", precision=22, scale=0) public Integer getFileType() { return this.fileType; } public void setFileType(Integer fileType) { this.fileType = fileType; } @Column(name="FILE_NAME", length=50) public String getFileName() { return this.fileName; } public void setFileName(String fileName) { this.fileName = fileName; } @JSON(serialize = false) @Lob @Basic(fetch = FetchType.LAZY) @Column(name="CONTENT") public byte[] getContent() { if (fieldHandler != null) { return (byte[]) fieldHandler.readObject(this, "content", content); } return null; } public void setContent(byte[] content) { this.content = content; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PublicSchemeTaskFile other = (PublicSchemeTaskFile) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; return true; } }
但是,僅僅是這樣,對導致需要用這個lazy fetch的欄位時,無法獲取到它的value,一直處於null 的狀態,這時候就需要用FieldHandler來處理了。
如下:
http://stackoverflow.com/questions/7902250/jpa-lazy-at-simple-byte-field-level
I've cheched it on Hibernate v.4.3.5 and JPA v.1.5.0, PostgreSQL 9.3. Worked like a charm. Example:
public class Attachment implements FieldHandled{ @Transient private FieldHandler fieldHandler; ... ... @Lob @Column(name=CONTENT, nullable=false) @Basic(fetch = FetchType.LAZY, optional = false) private byte[] content; ... ... public byte[] getContent() { if(fieldHandler!=null){ return (byte[])fieldHandler.readObject(this, "content", content); } return content; } public void setContent(byte[] content) { if(fieldHandler!=null){ fieldHandler.writeObject(this, "content", this.content, content); return; } this.content = content; } }