Java Hibernate.initialize() issue

最近同事遇到備份table(Model)某些幾筆資料會處於lazyinitializer狀態,欄位全是null的情形,
這幾筆正好都是在之前有get過其他Model然後該Model有@ManyToOne關連到這個table的,
由於是直接用dao.list()撈出來,dao裡面是單純的用session.createCriteria(clazz).list()做,
奇怪的是即使已經做了Hibernate.initialize(XXX),用debug看撈出來的XXX屬性還是null,
正當百思不得其解時,我用debug看getter XXX方法,結果竟然有值!
原來Hibernate.initialize()是對proxy做initialze,不是對該Model直接賦予值,因此還是要從getter拿屬性才會是正確的,
然後再看同事的備份table方法,是撈出來的Model List直接透過new ObjectMapper().writeValueAsString(list)轉成json,
這個list並沒有經過getter拿屬性,因此才會有幾筆lazyinitializer的資料欄位是null,
其實fetch = FetchType.LAZY屬性Hibernate session會從proxyByKey的Hashmap拿,這種必須透過getter才能真正拿到值,
(只要宣告成fetch = FetchType.LAZY的屬性都有機會變null,@OneToMany的屬性也是一樣,只是@ManyToOne是每次必變null)

所以備份table issue總結如下:
解法1:
不要偷懶全部屬性都用getter,但這樣每個屬性都要寫…

解法2:
還是維持new ObjectMapper().writeValueAsString(list)
做dao.list()之前先session.clear() –> 強迫session中斷就可以更新model,注意flush()或refresh()也沒用,一定要用clear()

解法3:
把XXX屬性的@ManyToOne(fetch = FetchType.LAZY)改成FetchType.EAGER
這樣每次撈此Model都會順便直接初始化XXX屬性

廣告

中國聯通APN

中國聯通APN存取點: 3GNET