如何定義實體java
持久化策略(或許也是整個應用)中最重要的就是實體定義。全部的對象都是從核心對象集合中繁衍而來的,所以正確的定義實體是很是重要的。下面是構建Hibernate/JPA實體方面個人一些建議。數據庫
1. 建立一個新類,實現java.io.Serializable接口(而且顯式定義serialVersionUID這個變量)。緩存
2. 增長類變量@Id Serializable id 和 @Version Date lastUpdated。這兩個變量分別是數據庫主鍵(primary key)和實現樂觀鎖(optimistic locking)的版本號標記。session
3. 增長任何須要的屬性。ide
4. 寫一個缺省的構造器。全部的類型的變量都應該在這裏初始化,包括集合(Collection),列表(List),集合(Set)等等工具
5. 爲全部的屬性建立getter和setter方法:單元測試
a) 應該爲id和lastUpdated建立public getter方法,可是不要建立setter方法。測試
b) 應該爲Collection、List、Set等類型的變量建立public getter方法,但不要建立setter方法。Public getter方法最好返回一個不能修改的list。ui
6. 增長JPA/Hibernate註解。給getter方法增長註解。(或者我能夠直接在變量上增長註解嗎?)spa
a) 添加Hibernate合法性註解,例如@NotNull、@Length、@Range等。
b) 即便名字相同,也應該添加@Column(name=xxx)註解。由於你確定不想忘記數據所依賴的最初的列名是什麼。
c) 在定義關係的實體中增長@OneToOne、@OneToMany、 @ManyToOne 或者@ManyToMany註解
7. 若是使用關係映射,確保其是雙向的(bidirectional)。簡單起見,我會建立工具方法(utility method)來處理關係映射的一端:集合(Collection)類型的屬性有工具方法 addXXX和removeXXX。(或許對應的關係映射的另外一端類的setter方法應該設爲受保護的(protected),而後從工具方法中調用)
8. 實現equal和hashcode方法。很是重要!
a) 這樣會使用id的方式來進行比較,從而減小比較次數。
b) 使用Hibernate.isInitialized()方法來判斷是否存在代理實例或者代理實例是否被初始化了。
c) 寫equal和hashcode方法時,不是全部的成員(field)都要用上,而是應該使用那些真正能夠區分不一樣對象的成員。
9. 用jakarta commons 的ToStringBuilder 構建本身的toString()方法,這樣可讓調試容易些。
10. 給Spring的配置文件增長一個映射元素。
get()方法和load()方法分析
Session#get() 和 Session#load()一個很重要的區別,就是對於數據庫讀取效率的影響不一樣。get()方法從數據庫返回一個對象實例,而load()方法則返回一個對象代理(proxy),當實際使用時才從當前session中返回對象實例。當使用load()時,是沒有實際訪問數據庫的。這個時候只是經過對象的屬性(非id)進行初始化工做。當進行實例賦值的時候使用load(),也就意味着並非想當即得到對象的數據,而是獲得一個標識符(identifier)從而創建起關聯。還有一點很重要,就是若是數據庫中不存在對應的行的時候使用load()方法,那麼程序會拋出ObjectNotFoundException異常。
單元測試斷言(Unit Testing Assertion)
單元測試時使用Session#flush() 和 Session#evict()分別向數據庫寫數據以及清除一級緩存(內存中),從而使得接下來的程序可以驗證修改是否被寫入了數據庫。evict()方法保證下次再去讀同一個實例時,拿到的不是一級緩存中的對象而是從數據庫裏拿出來的最新的對象。
Session#close()用來關閉當前session而且檢查延遲加載(lazy association)的狀態,若是沒有拿到指望的數據,那麼就會拋出一個LazyInitializationException異常。