bromon原創 請尊重版權 對象關係映射(Object Relative Mapping)簡稱ORM,是面向對象開發的一個熱點,用來解決JDBC開發中手動進行OR映射的繁雜與不便。EJB中的實體Bean在這個領域是很著名的——既因為它的先進而著名,也因為它的低效而著名。有過實體Bean開發經驗的人可能都會為實現遠程介面造成的效率低下而頭痛,在很多不大不小的項目中,使用實體Bean是否得不償失,爭論很大。一個輕量級的持久化方案也許能夠解決一些問題,Hibernate應此而生。 Hibernate是一個中間層,它的目的是把資料庫中的關係通過一定的規則映射成為對象,讓Java開發人員不用太多的考慮底層資料庫的問題,只需要像通常情況下管理對象一樣的管理數據。在關係資料庫仍將持續佔據市場的情況下,它很可觀。在數據持久化領域,即便是輕量級的方案也會是複雜饒舌的,也許如同周杰倫的音樂一樣不知所云。在學習它之前,最好先回想一下以前進行資料庫開發中遇到的問題和不便,想想為什麼需要一個持久化層,才能知道很多操作的目的是什麼,以及為什麼要這麼干,在這個問題上我不想做更多的敘述,因為「長久以來……」這樣的句式通常long(不好意思,打不出來)長,會對我的鍵盤和熱情造成很大的磨損。如果讓我寫一本書,那麼我會樂意去敘述什麼是數據持久化,它有什麼好處等等。廢話少說,來了。 首先需要配置環境,下載Hibernate 2.1(www.hibernate.org),把lib下的*.jar添加到classpath,你的資料庫JDBC驅動程序也應該在classpath中。打開hibernate.properties,針對你使用的資料庫,配置相應的信息,比如我使用的是MS SQL Server,配置如下: ## MS SQL Server hibernate.dialect net.sf.hibernate.dialect.SQLServerDialect hibernate.connection.driver_class com.microsoft.jdbc.sqlserver.SQLServerDriver hibernate.connection.url jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=zizz hibernate.connection.username sa hibernate.connection.password 其中很大部分是已經寫好的,只需要取掉註釋即可,我自己只是修改了資料庫名稱、帳號、密碼。建立一個名為zizz的資料庫備用。 然後把這個文件拷貝到你的應用的根目錄下。 我們談論了很多次映射,應該首先來看看這個映射是如何完成的。假設一個最簡單的應用,寫一個功能最單一的留言板,設計的數據有留言的編號、留言者名稱、留言內容,還有留言時間。足夠簡單吧,換做是你打算怎麼干?我猜你要首先建立一個資料庫表格,名字也許叫做guestbook。No,這不是面向對象的方式,不妨首先從對象的角度來考慮。我們當然希望每一條留言都以對象的方式呈現,每個對象應該具有的屬性有:id、author、content、time。偷個懶,沒有畫UML。下面這個類應該是很容易理解的: //GuestBook.java package org.bromon.zizz; import java.util.*; public class GuestBook { private int id; private String author; private String content; private Calendar time; private void setId(int id) { this.id=id; } public int getId() { return(id); } public void setAuthor(String author) { this.author=author; } public String getAuthro() { return(author); } public void setContent(String content) { this.content=content; } public String getContent() { return(content); } public void setTime(Calendar time) { this.time=time; } public Calendar getTime() { return(time); } } 基本上是最簡單的Bean了,如果覺得困難的話,請你先回火星等我。 需要注意的是setId方法被指定為private,這是因為我希望用這個欄位做主鍵,它最好由系統自動生成,所以不應該由用戶來指定,這個方法專為Hibernate準備,所以是私有的。 如何把這個類與資料庫映射起來?看看Hibernate的魔法,使用一個XML文件來描述,它應該被命名為GuestBook.hbm.xml: < ?xml version="1.0"? > < !DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "' target=_blank >http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" > < hibernate-mapping package="org.bromon.zizz" > < class name="GuestBook" table=」guestbook" lazy="true" > < id name="id" type="integer" unsaved-value="null" > < column name="id" sql-type="int" not-null="true"/ > < generator class="identity"/ > < /id > < property name="author" column="author" not-null="true" unique="false"/ > < property name="content" column="content" not-null="true"/ > < property name="time" column="time" not-null="true"/ > < /class > < /hibernate-mapping > 雖然有點陌生,但是很易讀,仔細琢磨一下。 下面來編寫我們的應用,它的功能是插入數據: //Operate.java package org.bromon.zizz; import net.sf.hibernate.*; import net.sf.hibernate.cfg.*; import net.sf.hibernate.tool.hbm2ddl.*; import java.util.*; public class Operate { public static void main(String args[]) { try { Configuration cfg=new Configuration().addClass(GuestBook.class); SessionFactory sessions=cfg.buildSessionFactory(); new SchemaExport(cfg).create(true,true); Session session=sessions.openSession(); GuestBook gb=new GuestBook(); gb.setAuthor(「Bromon」); gb.setContent(「留言的內容」); gb.setTime(Calendar.getInstance()); Transaction ts=session.beginTransaction(); session.save(gb); ts.commit(); session.close(); }catch(Exception e) { System.out.println(e); } } } 編譯吧:javac ?d . *.java 執行一下:java org.bromon.zizz.Operate 到資料庫裡面看看,表格已經建立好了,並且數據也已經保存。如果把 new SchemaExport().create(true,true); 註釋掉,那麼系統不會創建表格,而只是在已有的表格中添加新的記錄,當然,如果表格不存在的話,會產生異常。 你已經看到了Hibernate神奇魔法的5%,它足夠的複雜強大,可以讓你應付複雜的應用。 one-to-one關係 在絕大多數系統當中不可能只存在一個數據表格,否則就違背了關係資料庫的初衷。表與表的關係比較複雜,可以分為幾種情況: ● 一對一關聯(one to one) ● 一對多關聯(one to many) ● 多對一關聯(many to one) ● 多對多關聯(many to many) 按順序來講。假設一個一對一關聯的例子是: 表格:person id 編號(主鍵) name 姓名 email email地址 表格:spouse id 編號(外鍵) name 姓名 person這個表保存用戶信息,而spouse保存用戶配偶的信息。在一般情況下一個人只有一個配偶,這很適合我們一對一的情況。如果你對婚外戀感興趣的話,我們可以在一對多和多對一的關聯中討論這個問題,也許還可以在多對多中^_^(禽獸!)。 OK,下面設計POJO: Person這個類非常簡單: /* * Created on 2004-4-19 */ package org.bromon.zizz; /** * @author Bromon */ public class Person { private int id; private String name; private String email; public void setId(int id) { this.id=id; } public int getId() { return(id); } public void setName(String name) { this.name=name; } public String getName() { return(name); } public void setEmail(String email) { this.email=email; } public String getEmail() { return(email); } } 然後編寫它的映射規則,這個應該能夠理解了: < ?xml version="1.0"? > < !DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "' target=_blank >http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" > < hibernate-mapping package="org.bromon.zizz" > < class name="Person" table="person" lazy="true" > < id name="id" type="integer" unsaved-value="null" > < column name="id" sql-type="int" not-null="true"/ > < generator class="identity"/ > < /id > < property name="name" column="name" not-null="true" unique="false"/ > < property name="email" column="email" not-null="false"/ > < /class > < /hibernate-mapping > so easy是不是?一切都按部就班。下面是Souse類: /* * Created on 2004-4-20 */ package org.bromon.zizz; /** * @author Bromon */ public class Spouse { private int id; private String name; private Person person; public void setId(int id) { this.id=id; } public int getId() { return(id); } public void setName(String name) { this.name=name; } public String getName() { return(name); } public void setPerson(Person person) { this.person=person; } public Person getPerson() { return(person); } } 注意裡面的域person。它的映射文件: < ?xml version="1.0"? > < !DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "' target=_blank >http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" > < hibernate-mapping package="org.bromon.zizz" > < class name="Spouse" table="spouse" lazy="true" > < id name="id" type="integer" unsaved-value="null" > < column name="id" sql-type="int" not-null="true"/ > < generator class="foreign" > < param name="property" >person< /param > < /generator > < /id > < property name="name" column="name" not-null="true" unique="false"/ > < one-to-one name="person" class="Person" cascade="all" constrained="true" / > < /class > < /hibernate-mapping > 這裡指明了id的generator是一個外鍵,和person相關聯。然後指定一個one-to-one關係,不難理解是不是?Hibernate的確很符合我們的思維習慣。需要提醒的是,這種關聯關係是單向的,Person並不需要去指定Spouse。 下面來操作這兩個類: /* * Created on 2004-4-20 */ package org.bromon.zizz; import net.sf.hibernate.*; import net.sf.hibernate.cfg.*; import net.sf.hibernate.tool.hbm2ddl.*; /** * @author Bromon */ public class OperateSpouse { public static void main(String args[]) { try { Configuration cfg=new Configuration().addClass(Spouse.class); cfg.addClass(Person.class); SessionFactory factory=cfg.buildSessionFactory(); new SchemaExport(cfg).create(true,true); Session session=factory.openSession(); Person person=new Person(); person.setName("bromon"); person.setEmail("bromon@163.com"); Spouse spouse=new Spouse(); spouse.setName("who"); spouse.setPerson(person); Transaction ts=session.beginTransaction(); session.save(person); session.save(spouse); ts.commit(); session.close(); }catch(Exception e) { System.out.println(e); } } } 這個例子和第一篇中的例子非常相似。OK,執行一下,然後看看zizz資料庫,搞掂。 Many-to-One關係 很明顯一對多或者多對一關係是關係資料庫中非常常見的現象,下面通過父親-兒子的例子來演示一對多關係,多對一關係是類似的,不過在我們的這個例子中不宜採用,否則會帶來倫理學上的問題。 首先定義Child類: /* * Created on 2004-5-8 */ package org.bromon.zizz; /** * @author Bromon */ public class Child { private int id; private String name; private int fatherId; private Person father; public Child(){} /** * @return */ public Person getFather() { return father; } /** * @return */ public int getFatherId() { return fatherId; } /** * @return */ public int getId() { return id; } /** * @return */ public String getName() { return name; } /** * @param person */ public void setFather(Person p) { father = p; } /** * @param i */ public void setFatherId(int i) { fatherId = i; } /** * @param i */ public void setId(int i) { id = i; } /** * @param string */ public void setName(String string) { name = string; } } 這裡的fatherId是外鍵,關聯person表的id欄位。 下面是映射文件Child.hbm.xml: < ?xml version="1.0"? > < !DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "' target=_blank >http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" > < hibernate-mapping package="org.bromon.zizz" > < class name="Child" table="child" lazy="true" > < id name="id" type="integer" unsaved-value="null" > < column name="id" sql-type="int" not-null="true"/ > < generator class="identity"/ > < /id > < property name="name" column="name" not-null="true" unique="false"/ > < many-to-one name="father" column="fatherid" / > < /class > < /hibernate-mapping > 需要注意的是fatherId並沒有做為一個property被映射,而是在many-to-one聲明中使用。 需要對Person..java做修改,添加以下代碼: import java.util.*; private Set children=new HashSet(); /** * @return */ public Set getChildren() { return children; } /** * @param set */ public void setChildren(Set set) { children = set; } 然後修改Person.hbm.xml,對添加的代碼做映射: < set name="books" lazy="true" inverse="true" cascade="all" > < key column="fatherid"/ > < one-to-many class="Child" / > < /set > 這裡的key column是child表的外鍵,inverse需要指定為true。 下面做操作一下,功能是查詢person表中id=1的記錄,作為小孩的父親,然後給child表添加一條新記錄。 /* * Created on 2004-5-8 */ package org.bromon.zizz; import net.sf.hibernate.*; import net.sf.hibernate.cfg.*; import net.sf.hibernate.tool.hbm2ddl.*; /** * @author Bromon */ public class OperateChild { /** * @param args */ public static void main(String args[]) { try { Configuration cfg = new Configuration().addClass(Person.class); cfg.addClass(Child.class); SessionFactory sessions = cfg.buildSessionFactory(); new SchemaExport(cfg).create(true, true); Session session = sessions.openSession(); Child c=new Child(); /*Query q=session.createQuery("from org.bromon.zizz.Person as p where p.id=1"); Person p=(Person)q.list().get(0);*/ Person p=(Person)session.find("from org.bromon.zizz.Person as p where p.id=?",new Integer(1),Hibernate.INTEGER).get(0); System.out.println(p.getName()); c.setName("andy"); c.setFather(p); Transaction ts = session.beginTransaction(); session.save(c); ts.commit(); session.close(); } catch (Exception e) { System.out.println(e); } } } 被註釋掉的部分是HQL的另外一種查詢方法。在這個例子中可以看出對象的查詢非常容易,不需要自己再去封裝數據,修改和刪除對象也很容易: //得到一個對象 Query q=session.createQuery("from org.bromon.zizz.Person as p where p.id=1"); Person p=(Person)q.list().get(0); //修改數據 p.setName(「Mr Smith」); //保存數據 session.save(p); session.flush(); //刪除數據 session.delete(p); session.flush();
[火星人
]
Java企業應用-Hibernate實戰全解 已經有795 次圍觀
本文地址: http://coctec.com/docs/linux/show-post-189728.html