国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

別讓Hibernate偷走了你的標識符

2019-11-18 14:43:15
字體:
來源:轉載
供稿:網友
摘要:

  當對象持久化到數據庫中時,對象的標識符總時很難被恰當的實現。盡管如此,問題其實完全是由存在著在保存之前不持有ID的對象的現象衍生而來的。我們可以通過從諸如Hibernate這樣的對象—關系映像框架手中取走指派對象ID的職責來解決這個問題。相對的,一旦對象被實例化,它就應該被指派一個ID。這使對象標識符變成簡單而不易出錯,也減少了領域模型中需要的代碼量。

  企業級java應用程序經常把數據在java對象和關系型數據庫之間往返移動。從手動編寫SQL代碼到使用諸如hibernate這樣的成熟的對象---關系映像(ORM)解決方案,有很多種方法可以實現這個過程。無論你采用什么樣的技術,一旦你開始將java對象持久化到數據庫中,對象標識符都將成為一個復雜而且難以治理的課題。可能出現的情況是:你實例化了兩個不同的對象,而它們卻代表了數據庫中的同一行。為了解決這個問題,你可能采取的措施是在你的持久化對象中實現equals() 和hashCode()這兩個方法,可是要恰當的實現這兩個方法比乍看之下要有技巧一些。讓問題更糟糕的是,那些傳統的思路(包括hibernate官方文檔所提倡的那些)對于新的工程并不一定能提出最實用的解決方案。

  對象標識在虛擬機(VM)中和在數據庫中的差異是問題滋生的溫床。在虛擬機中,你并不會得到對象的id,你只是簡單的持有對象的直接引用。而在幕后,虛擬機確實給每個對象指派了一個8字節大小的id,這個id才是對象的真實引用。當你將對象持久化到數據庫中的時候,問題開始產生了。假定你創建了一個Person對象并將它存入數據庫(我們可以叫它person1)。而你的其它某段代碼從數據庫中讀取了這個Person對象的數據并將它實例化為另一個新的Person對象(我們可以叫它Person2)。現在你的內存中有了兩個映像到數據庫中同一行的對象。一個對象引用只能指向它們倆的其中一個,可是我們需要一種方法來表示這兩個對象實際上表示著同一個實體。這就是(在虛擬機中)引入對象標識符的原因。

  在java語言中,對象標識符是由每個對象都持有的equals()方法(以及相關的hashCode()方法)來定義的。無論兩個對象(引用)是否為同一個實例,equals()方法都應該能夠判別出它們是否表示同一個實體。hashCode()方法和equals()方法有關聯是因為所有被判定等價(equal)的對象都應該返回相同的哈希值(hashCode)。在缺省實現中,equals()方法僅僅比較對象的引用,一個對象和它自身是等價的,而和其它任何實例都不等價。對于持久化對象來說,重寫這兩個方法,讓代表著數據庫中同一行的兩個對象被判為等價是很重要的。而這對于java中的Collection數據結構(Set,Map和List)的正確工作更是尤為重要。

  為了闡明實現equal()和hashCode()的不同途徑,讓我們一起考慮一個預備持久化到數據庫中的簡單對象Person。

public class Person {
 PRivate Long id;
 private Integer version;
 public Long getId() { return id; }
 public void setId(Long id) {
  this.id = id;
 }
 public Integer getVersion() {
  return version;
 }
 public void setVersion(Integer version) {
  this.version = version;
 }
 // person-specific properties and behavior
}
  在這個例子中,我們遵循了同時持有id字段和version字段的最佳實踐。Id字段保存了在數據庫中作為主鍵使用的值,而version字段則是一個從0開始增長的增量,隨著對象的每次更新而變化(它幫助我們避免并發更新的問題)。為了看的更清楚,我們也一起看一下Hibernate把這個對象持久化到數據庫的映像文件。

<?xml version="1.0"?>
<hibernate-mapping package="my.package">
<class name="Person" table="PERSON">
<id name="id" column="ID" unsaved-value="null">
<generator class="sequence">
<param name="sequence">PERSON_SEQ</param>
</generator>
</id>
<version name="version" column="VERSION" />
<!-- Map Person-specific properties here. -->
</class>
</hibernate-mapping>
  Hibernate映像文件指明了Person的id字段代表了數據庫中的ID列(也就是說,它是PERSON表的主鍵)。包含在id標簽中的unsaved-value="null"屬性告訴Hibernate使用id字段來判定一個Person對象之前是否被保存過。ORM框架必須依靠這個來判定保存一個對象的時候應該使用SQL的INSERT字句還是UPDATE字句。在這個例子中,Hibernate假定一個新對象的id字段一開始為null值,當它第一次被保存時才id才被賦予一個值。generator標簽告訴Hibernate當對象第一次保存時,應該從哪里獲得指派的id。在這個例子中,Hibernate使用數據庫序列作為產生唯一id的來源。最后,version標簽告訴Hibernate使用Person對象的version字段進行并發控制。Hibernate將會執行樂觀鎖方案(optimistic locking scheme),根據這個方案,Hibernate在保存對象之前會檢查對比對象的version值和數據庫中相應數據的version值。

  我們的Person對象還缺少的是equals()方法和hashCode()方法的實現。既然這是一個持久化對象,我們并不想依靠于這兩個方法的缺省實現,因為缺省實現并不能分辨代表數據庫中同一實體的不同實例。一種簡單而又顯然的實現方法是利用id字段來進行equal()方法的比較以及生成hashCode()方法的結果。



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 上高县| 汶上县| 耿马| 孙吴县| 台前县| 兴城市| 峨边| 竹山县| 隆德县| 五峰| 衡水市| 湖北省| 隆昌县| 大宁县| 务川| 海口市| 通榆县| 高雄市| 洛川县| 平舆县| 七台河市| 灵寿县| 仁寿县| 疏勒县| 西华县| 贞丰县| 高陵县| 枞阳县| 巴塘县| 中超| 瑞金市| 柞水县| 文水县| 贵德县| 奉节县| 潜江市| 兴安盟| 神农架林区| 沁源县| 溧水县| 宁德市|