俗話說,本身寫的代碼,6個月後也是別人的代碼……複習!複習!複習!涉及的知識點總結以下:java
自動生成數據庫腳本web
通常在項目開發過程當中,咱們的習慣是先建好數據庫和表,而後在進行開發,而hibernate做爲一款ORM架構模式的實現框架,咱們要好好利用,能夠利用hibernate反向工程生成*.hbm.xml文件跟POJO類,我的認爲因爲目前所使用的數據庫大部分還都是關係數據庫,而hibernate把對數據庫的操做都對象化了,更應當從對象出發,生成數據庫裏面相關表,這樣更加符合人認知事物的習慣,hibernate3就已經提供了自帶的工具hbm2ddl,可以經過對象創建數據庫腳本。sql
要生成數據庫表,得先建好實體類,而後創建對應的配置文件(or 註解),最後和主配置文件hibernate.cfg.xml關聯便可。做用的代碼以下:數據庫
SchemaExport se = new SchemaExport(new AnnotationConfiguration().configure()); // 生成,並輸出sql到文件(當前目錄)和數據庫, 建立表結構,第一個true 表示在控制檯打印sql語句,第二個true 表示導入sql語句到數據庫 se.create(true, true);
這就是領域驅動設計/開發(DDD,Domain Driven Design/Development)。api
系統的設計應該基於對象模型,考慮對象的設計和邏輯,而後按照對象模型創建數據庫關係模型,這纔是如今面向對象開發的步驟,不是說先設計數據庫,而後再設計對象。當在設計時,咱們的領域模型須要改變,只需修改Hibernate的結構和應用程序,不須要修改數據庫架構,只要利用SchemaExport工具從新生成數據庫架構就ok。session
一對一的單向外鍵關係架構
好比一我的對應一張身份證,反過來一張身份證必須對應一我的,不存在歧義。一個學生類,一個身份證類,學生惟一對應一張身份證,反過來,身份證惟一表示一個學生。這就是一對一的關係,其中學生能持有身份證,故學生表裏的身份證的id就是學生表的外鍵,學生id是學生表的主鍵。這也叫一對一單向外鍵關係。app
註解方式:實體類和配置以下:框架
import org.hibernate.annotations.GenericGenerator; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; // 身份證類 @Entity public class IdCard { private String pid;// 身份證號碼 private String province;// 省份 @Id @GeneratedValue(generator="pid")// 聲明一個主鍵生成策略, 須要用到下面的hibernate的主鍵生成策略,叫pid @GenericGenerator(name="pid",strategy="assigned") // 聲明一個主鍵生成策略,身份證須要手工指定,設置主鍵生成器的名字,必須是pid // @GeneratedValue的做用是JPA的默認實現自定義主鍵生成策略,@GenericGenerator是hibernate在JPA的基礎上加強。 public String getPid() { return pid; } public void setPid(String pid) { this.pid = pid; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } }
下面是學生類:dom
import javax.persistence.*; // 學生實體類 @Entity public class Students { private int sid; // 學生編號 private String sname; private IdCard cardId; // 身份證 @OneToOne(cascade = CascadeType.ALL) // 設置學生表的外鍵:一對一單向外鍵(Annotation),設置爲所有級聯更新 @JoinColumn(name = "pid",unique=true) // 在主表中加入外鍵pid,惟一的 public IdCard getCardId() { return cardId; } public void setCardId(IdCard cardId) { this.cardId = cardId; } @Id @GeneratedValue(strategy = GenerationType.AUTO) // 學生類的主鍵由於是整型,故設置自動增加 //@GeneratedValue // 不寫其實也ok、至關於上面的效果,也就是默認是auto(MySQL的native類型) public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } }
最後反向生成數據庫表。注意:一對一的關係,必須先保存外鍵的對象,再保存主鍵的對象,完整的CRUD的代碼以下
import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.classic.Session; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestStudentsByAnno{ private static final Logger LOG = LoggerFactory.getLogger(TestStudentsByAnno.class); private static SessionFactory sessionFactory; @Before public void setUp() { LOG.info("setUp"); AnnotationConfiguration annotationConfiguration = new AnnotationConfiguration().configure(); sessionFactory = annotationConfiguration.buildSessionFactory(); testSchemaExport(annotationConfiguration); } @After public void tearDown() { LOG.info("tearDown"); sessionFactory.close(); } @Test public void testSave() { Session session = sessionFactory.getCurrentSession(); Transaction tx = session.beginTransaction(); try { IdCard c = new IdCard(); c.setPid("66666666666"); c.setProvince("shanxi"); Students s = new Students(); s.setSname("zhangsan"); s.setCardId(c); //先保存身份證 session.save(c); //再保存學生 session.save(s); tx.commit(); } catch(Exception ex) { ex.printStackTrace(); tx.rollback(); } } private void testSchemaExport(AnnotationConfiguration annotationConfiguration) { LOG.info("=============================testSchemaExport"); SchemaExport se = new SchemaExport(annotationConfiguration); // 生成,並輸出sql到文件(當前目錄)和數據庫, 建立表結構,第一個true 表示在控制檯打印sql語句,第二個true 表示導入sql語句到數據庫 se.create(true, true); } }
Hibernate: insert into IdCard (province, pid) values (?, ?)
Hibernate: insert into Students (pid, sname) values (?, ?)
XML配置方式:注意主控方的配置文件裏須要加上<many-to-one name="cardId" column="pid" unique="true"/>,主控方就是持有惟一外鍵的那個表,name=外鍵id,保持惟一,由於一對一,必須設置爲unique爲true!
身份證的配置:
<hibernate-mapping> <class name="net.nw.vo.fk.IdCard" table="idcard"> <id name="pid" column="pid" type="string"> <generator class="assigned"/> </id> <property name="province" column="province" type="string"/> </class> </hibernate-mapping>
學生的配置:做爲主控方,須要加上一對一的關係映射屬性,使用的是many-to-one標籤
<hibernate-mapping> <class name="net.nw.vo.fk.Students" table="students"> <id name="sid" column="sid" type="int"> <generator class="native"/> </id> <property name="sname" column="sname" type="string"/> <many-to-one name="cardId" column="pid" unique="true"/> </class> </hibernate-mapping>
還有主配置文件的關聯,下面是測試代碼:
public void testSave() { Session session = sessionFactory.getCurrentSession(); Transaction tx = session.beginTransaction(); try { IdCard c = new IdCard(); c.setPid("1111111111"); c.setProvince("dadadada"); Students s = new Students(); s.setSname("daaaaaaa"); s.setCardId(c); //先保存身份證 session.save(c); //再保存學生 session.save(s); tx.commit(); } catch(Exception ex) { ex.printStackTrace(); tx.rollback(); } }
成功插入了數據
一對一雙向外鍵關聯
很簡單,能夠理解爲雙方都持有對方的引用,也就是你中有我,我中有你的一對一關聯關係,好比學生表包含身份證id,同時身份證表也包含學生id,同時互爲對方的外鍵。
註解方式:實體類和配置以下:
兩個實體類其中之一必須使用註解:@OneToOne(mappedBy=「實體類的引用」) ,屬性mappedBy是必須的,目的是設置將控制權交給另一方(實體類)。雙向的關聯必須設置mappedBy屬性。也就是說雙向關聯只能交給一方去控制,不可能在雙方都設置外鍵保存關聯關係,不然都沒法保存。由於學生表包含身份證id,同時身份證表也包含學生id,互爲對方的外鍵。若是互爲主控方,那麼先保存誰呢?若是要保存學生,則應該先保存身份證,而身份證也是主控方,要保存身份證必須先保存學生……死循環發生。
1 import javax.persistence.*; 2 3 //學生實體類 4 @Entity 5 public class Students { 6 private int sid; //編號 7 8 private String sname; //姓名 9 10 private IdCard cardId; // 學生持有身份證的引用,由於學生表關聯了身份證表 11 12 // cascade屬性須要設置爲all,代表刪除student時同時刪除對應的身份證 13 @OneToOne(cascade = CascadeType.ALL) // 本例子裏學生做爲主控方,則須要在身份證類那兒聲明mappedBy屬性 14 @JoinColumn(name="pid",unique=true) // 學生表的外鍵是身份證id:pid,惟一的 15 public IdCard getCardId() { 16 return cardId; 17 } 18 19 public void setCardId(IdCard cardId) { 20 this.cardId = cardId; 21 } 22 23 @Id 24 @GeneratedValue 25 // 默認 等價於 @GeneratedValue(strategy=GenerationType.AUTO) 26 public int getSid() { 27 return sid; 28 } 29 30 public void setSid(int sid) { 31 this.sid = sid; 32 } 33 34 public String getSname() { 35 return sname; 36 } 37 38 public void setSname(String sname) { 39 this.sname = sname; 40 } 41 }
本例子裏學生表(實體類)做爲主控方,那麼本類不須要設置@OneToOne(mappedBy=「」),而是須要在另外一方——身份證類裏聲明@OneToOne(mappedBy=「」)屬性
1 import org.hibernate.annotations.GenericGenerator; 2 import javax.persistence.*; 3 4 //身份證類 5 @Entity 6 public class IdCard { 7 private String pid;//身份證號碼 8 9 private String province;//省份 10 11 private Students stu;//反過來身份證表也關聯學生表,對應程序也就是身份證類包含學生對象的引用 12 13 // 身份證把控制權交給學生控制,mappedBy值是主控方持有的引用(外鍵) 14 // 記住:只要雙向關聯,必須雙方有一方要指定mappedBy屬性,不能互相指定,目的是避免死循環發生 15 @OneToOne(mappedBy="cardId") 16 public Students getStu() { 17 return stu; 18 } 19 20 public void setStu(Students stu) { 21 this.stu = stu; 22 } 23 24 @Id 25 @GeneratedValue(generator="pid") 26 @GenericGenerator(name="pid",strategy="assigned") 27 public String getPid() { 28 return pid; 29 } 30 31 public void setPid(String pid) { 32 this.pid = pid; 33 } 34 35 public String getProvince() { 36 return province; 37 } 38 39 public void setProvince(String province) { 40 this.province = province; 41 } 42 }
測試生成數據庫腳本:
alter table Students drop foreign key FK73AC29B8917F52BE drop table if exists IdCard drop table if exists Students create table IdCard (pid varchar(255) not null, province varchar(255), primary key (pid)) create table Students (sid integer not null auto_increment, sname varchar(255), pid varchar(255) unique, primary key (sid)) alter table Students add index FK73AC29B8917F52BE (pid), add constraint FK73AC29B8917F52BE foreign key (pid) references IdCard (pid)
我發現其實和剛剛一對一單向外鍵關聯的表結構同樣,好像沒什麼區別啊?其實關鍵問題是所謂的一對一雙向關聯,就是實體類裏雖然彼此包含了對方的引用,可是在實際設計數據庫時的關鍵問題是——把控制權交給誰?上例把IdCard的stu交給了學生類去控制,若是反過來,學生類stu的身份證pid交給身份證去控制,看代碼:
1 import org.hibernate.annotations.GenericGenerator; 2 import javax.persistence.*; 3 4 //身份證類 5 @Entity 6 public class IdCard { 7 private String pid;//身份證號碼 8 9 private String province;//省份 10 11 private Students stu;//反過來身份證表也關聯學生表,對應程序也就是身份證類包含學生對象的引用 12 13 @OneToOne(cascade=CascadeType.ALL) // 如今身份證是主控方 14 @JoinColumn(name="sid",unique=true) 15 public Students getStu() { 16 return stu; 17 } 18 19 public void setStu(Students stu) { 20 this.stu = stu; 21 } 22 23 @Id 24 @GeneratedValue(generator="pid") 25 @GenericGenerator(name="pid",strategy="assigned") 26 public String getPid() { 27 return pid; 28 } 29 30 public void setPid(String pid) { 31 this.pid = pid; 32 } 33 34 public String getProvince() { 35 return province; 36 } 37 38 public void setProvince(String province) { 39 this.province = province; 40 } 41 }
主控方交給身份證
1 import javax.persistence.*; 2 3 //學生實體類 4 @Entity 5 public class Students { 6 private int sid; //編號 7 8 private String sname; //姓名 9 10 private IdCard cardId; // 學生持有身份證,學生表關聯了身份證表 11 12 @OneToOne(mappedBy="stu") // 學生持有的身份證把控制權交給身份證控制 13 public IdCard getCardId() { 14 return cardId; 15 } 16 17 public void setCardId(IdCard cardId) { 18 this.cardId = cardId; 19 } 20 21 @Id 22 @GeneratedValue 23 // 默認 等價於 @GeneratedValue(strategy=GenerationType.AUTO) 24 public int getSid() { 25 return sid; 26 } 27 28 public void setSid(int sid) { 29 this.sid = sid; 30 } 31 32 public String getSname() { 33 return sname; 34 } 35 36 public void setSname(String sname) { 37 this.sname = sname; 38 } 39 }
測試數據庫腳本,發現和剛剛不同了,身份證裏有外鍵sid,而學生表沒有了以前的外鍵pid,說明身份證去控制學生了。
create table IdCard (pid varchar(255) not null, province varchar(255), sid integer unique, primary key (pid)) create table Students (sid integer not null auto_increment, sname varchar(255), primary key (sid))
注意:千萬別讓雙方都持有對方的引用做爲外鍵,這樣是沒有意義的。雖然語法不會出錯,執行起來確定會出死循環的問題。繼續測試,如今是身份證控制學生,那麼先保存學生(學生id是外鍵),在保存身份證:
1 import org.hibernate.Session; 2 import org.hibernate.SessionFactory; 3 import org.hibernate.Transaction; 4 import org.hibernate.cfg.AnnotationConfiguration; 5 import org.hibernate.cfg.Configuration; 6 import org.hibernate.tool.hbm2ddl.SchemaExport; 7 import org.junit.After; 8 import org.junit.Before; 9 import org.junit.Ignore; 10 import org.junit.Test; 11 12 public class TestStudentsByAnno { 13 private static SessionFactory sessionFactory; 14 15 @Before 16 public void setUp() throws Exception { 17 System.out.println("setUp()..."); 18 sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); 19 } 20 21 @After 22 public void tearDown() throws Exception { 23 System.out.println("tearDown()..."); 24 sessionFactory.close(); 25 } 26 27 @Test 28 29 public void testSave() { 30 Session session = sessionFactory.getCurrentSession(); 31 Transaction tx = session.beginTransaction(); 32 33 try { 34 Students s = new Students(); 35 s.setSname("xiaoli"); 36 IdCard c = new IdCard(); 37 c.setPid("12345656788"); 38 c.setProvince("hebei"); 39 c.setStu(s); 40 //先保存學生 41 session.save(s); 42 //再保存身份證 43 session.save(c); 44 45 tx.commit(); 46 } catch(Exception ex) { 47 ex.printStackTrace(); 48 tx.rollback(); 49 } 50 } 51 52 @Test 53 @Ignore 54 public void testSchemaExport() { 55 SchemaExport se = new SchemaExport(new Configuration().configure()); 56 se.create(true, true); 57 } 58 }
結果:
XML配置方式:實體類和配置以下:
大同小異,理解了註解的方式,xml就是書寫的注意,主控方仍是和以前一對一單向管理的寫法同樣:<many-to-one name="cardId" column="pid" unique="true"/>,被控方須要注意下,要寫成<one-to-one name="stu" property-ref="cardId"/>,下面實現一個學生爲主控方的例子:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="net.nw.vo.bfk.Students" table="students"> <id name="sid" column="sid" type="int"> <generator class="native"/> </id> <property name="sname" column="sname" type="string"/> <!-- 主控方,外鍵是身份證pid --> <many-to-one name="cardId" column="pid" unique="true"/> </class> </hibernate-mapping> ----------------------------------------------------------------------------- <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="net.nw.vo.bfk.IdCard" table="idcard"> <id name="pid" column="pid" type="string"> <generator class="assigned"/> </id> <property name="province" column="province" type="string"/> <!-- 身份證是被控的,也須要配置,使用one-to-one屬性 property-ref意思是把控制交給學生類,讓學生使用cardId這個身份證的引用去控制 --> <one-to-one name="stu" property-ref="cardId"/> </class> </hibernate-mapping>
實體類不變,仍是互相持有對方的引用,而後測試也是注意,先保存外鍵的實體類身份證,最後保存學生類:
IdCard c = new IdCard(); c.setPid("999999999"); c.setProvince("beijing"); Students s = new Students(); s.setSname("wangwu"); s.setCardId(c); //先保存身份證 session.save(c); //再保存學生 session.save(s); tx.commit();
什麼是聯合主鍵?
聯合主鍵就是用多個字段組成的主鍵。用這個主鍵包含的字段做爲主鍵,這個組合在數據表中是惟一,且加了主鍵索引。好比,訂單表裏有不少字段,通常狀況只要有個訂單號作主鍵就能夠,可是如今可能會有補充訂單,使用相同的訂單號,那麼這時單獨使用訂單號就不能夠,由於會有重複。那麼能夠再使用個訂單序列號做爲區別。把訂單號和訂單序列號設成聯合主鍵。即便訂單號相同,訂單序列號不一樣也是能夠惟一的。
一對一單向外鍵聯合主鍵關聯
註解方式:實體類和配置以下:
先建立聯合主鍵類,須實現serializable接口,進行序列化,還必須重寫hashCode()和equals()方法。聯合主鍵類的註解是@Embeddable,使能嵌入的意思,而實體類的主鍵使用@EmbeddedId標識,代碼以下:
import javax.persistence.Embeddable; import java.io.Serializable; //聯合主鍵類的註解是 Xxxxable 類型,嵌入的意思 @Embeddable public class IdCardPK implements Serializable{ /** * 必須實現序列化接口 */ private static final long serialVersionUID = 1L; private String pid;//身份證號碼,主鍵字段 private String bloodType;//新加的字段:血型,也做爲主鍵字段 public String getPid() { return pid; } public void setPid(String pid) { this.pid = pid; } public String getBloodType() { return bloodType; } public void setBloodType(String bloodType) { this.bloodType = bloodType; } /** * 必須重寫equals和hashCode * * @param obj Object * @return boolean */ @Override public boolean equals(Object obj) { return super.equals(obj); } @Override public int hashCode() { return super.hashCode(); } }
再建立對應的實體類:
1 import javax.persistence.EmbeddedId; 2 import javax.persistence.Entity; 3 import javax.persistence.OneToOne; 4 5 //身份證明體類 6 @Entity 7 public class IdCard { 8 private IdCardPK pk;// 身份證的主鍵是聯合主鍵 IdCardPK pk 9 10 private String province;// 省份 11 12 private Students stu; // 身份證持有學生類的引用 13 14 // 把控制權交給學生 15 @OneToOne(mappedBy="cardId")//只要是雙向關聯,就必定要指定mappedBy 16 public Students getStu() { 17 return stu; 18 } 19 20 public void setStu(Students stu) { 21 this.stu = stu; 22 } 23 24 // 聯合主鍵的主鍵形式是Xxxxid類型,具體的主鍵設置在聯合主鍵類裏進行 25 @EmbeddedId 26 public IdCardPK getPk() { 27 return pk; 28 } 29 30 public void setPk(IdCardPK pk) { 31 this.pk = pk; 32 } 33 34 public String getProvince() { 35 return province; 36 } 37 38 public void setProvince(String province) { 39 this.province = province; 40 } 41 } 42 43 import javax.persistence.CascadeType; 44 import javax.persistence.Entity; 45 import javax.persistence.GeneratedValue; 46 import javax.persistence.Id; 47 import javax.persistence.JoinColumn; 48 import javax.persistence.JoinColumns; 49 import javax.persistence.OneToOne; 50 51 //學生實體類 52 @Entity 53 public class Students { 54 private int sid; //編號 55 56 private String sname; //姓名 57 58 private IdCard cardId; // 學生的外鍵,學生控制身份證 59 60 // 主控類的外鍵設置比較複雜點,由於有多個主鍵字段了 61 @OneToOne(cascade=CascadeType.ALL) 62 @JoinColumns( 63 { 64 // referencedColumnName設置對應數據庫的字段名字,name是類的字段名字 65 @JoinColumn(name="pid",referencedColumnName="pid"), 66 @JoinColumn(name="bloodType",referencedColumnName="bloodtype") 67 } 68 ) 69 public IdCard getCardId() { 70 return cardId; 71 } 72 73 public void setCardId(IdCard cardId) { 74 this.cardId = cardId; 75 } 76 77 @Id 78 @GeneratedValue 79 public int getSid() { 80 return sid; 81 } 82 83 public void setSid(int sid) { 84 this.sid = sid; 85 } 86 87 public String getSname() { 88 return sname; 89 } 90 91 public void setSname(String sname) { 92 this.sname = sname; 93 } 94 }
注意千萬別忘了配置hibernate主文件:
<mapping class="net.nw.vo.ufk.Students" /> <mapping class="net.nw.vo.ufk.IdCard" /> <mapping class="net.nw.vo.ufk.IdCardPK" />
生成的數據庫腳本:
create table IdCard (bloodType varchar(255) not null, pid varchar(255) not null, province varchar(255), primary key (bloodType, pid))
create table Students (sid integer not null auto_increment, sname varchar(255), bloodType varchar(255), pid varchar(255), primary key (sid))
一樣保存數據也是先保存受控類,在保存主控類。
XML配置方式:實體類和配置以下:
理解了上述主鍵的意思,xml也就很簡單了:
被控方:
<composite-id name="pk" class="聯合主鍵的類"> <key-property name="pid" column="pid" type="string"/> <key-property name="bloodType" type="string"/> <generator class="assigned"></generator> </composite-id>
主控方:
<many-to-one name="cardId"> <column name="pid" unique="true"/> <column name="bloodid"/> </many-to-one>
注意,聯合主鍵類不須要單獨的映射文件進行配置!代碼以下:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="net.nw.vo.ufk.IdCard" table="idcard"> <!-- 聯合主鍵的配置 --> <composite-id name="pk" class="net.nw.vo.ufk.IdCardPK"> <key-property name="pid" column="pid" type="string"/> <key-property name="bloodType" type="string"/> <generator class="assigned"/> </composite-id> <property name="province" column="province" type="string"/> </class> </hibernate-mapping> ------------------------------------------------------------------ <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- 主控方--> <class name="net.nw.vo.ufk.Students" table="students"> <id name="sid" column="sid" type="int"> <generator class="native"/> </id> <property name="sname" column="sname" type="string"/> <!-- 主控方的外鍵 --> <many-to-one name="cardId"> <!-- 該外鍵的表又包含聯合主鍵 --> <column name="pid" unique="true"/> <column name="bloodid"/> </many-to-one> </class> </hibernate-mapping>
一對一組件關聯映射
組件類就是一個POJO類,什麼主鍵或者映射配置都不須要!由於實際上就是隻有一張表,是最簡單的,先不說理論,看例子:
註解方式:實體類和配置以下:
IdCard裏什麼主鍵都不寫,固然配置也不須要,就是一個POJO類
//身份證類,就是一個POJO類 public class IdCard { private String pid;//身份證號碼 private String province;//省份 public String getPid() { return pid; } public void setPid(String pid) { this.pid = pid; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } }
只有被組件注入的實體類須要配置,它的主鍵註解爲@Embedded
import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; //學生實體類 @Entity public class Students { private int sid; //編號 private String sname; //姓名 private IdCard cardId; @Id @GeneratedValue public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } @Embedded public IdCard getCardId() { return cardId; } public void setCardId(IdCard cardId) { this.cardId = cardId; } }
執行數據庫腳本:
drop table if exists Students
create table Students (sid integer not null auto_increment, pid varchar(255), province varchar(255), sname varchar(255), primary key (sid))
執行插入測試:
IdCard c = new IdCard(); c.setPid("1234567"); c.setProvince("hebei"); Students s = new Students(); s.setSname("a"); s.setCardId(c); session.save(s); tx.commit();
開始扯理論:如何理解組件?
組件是某個實體類的邏輯組成部分,這個組件與實體的本質區別在於組件沒有oid(參考前面的例子,它沒有任何配置),故能夠理解爲能把組件當作值對象。例子中把省份和身份證id單獨提取抽象出來做爲了一個組件類,這個類就叫作值對象,也就是所說的組件。
採用組件映射的優勢
實現了對象細粒度的劃分,層次更加分明,複用率高。上面的student類,分爲了基本信息sid、sname,還將身份證分離了出來,此外,還能夠將愛好,家庭成員等信息再做爲一類分離出來,進行細粒度的劃分。分離出來的組件,也能夠做爲其餘對象(例如teacher、employer等)的組件,這樣就爲複用提供了方便。
XML配置方式:實體類和配置以下:
映射關係文件:
<component name="cardId" class="net.nw.vo.component.IdCard">
<property name="pid" column="pid" type="string"></property>
<property name="province" type="string"></property>
</component>
映射文件中,經過<component>標籤,將組件類的屬性映射到學生表中,這樣,student表中的字段就會是Student類中的sid、sname以及組件類中的pid和provincel。而在數據庫中,身份證類不用單首創建一張表。代碼以下:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="net.nw.vo.bfk.Students" table="students"> <id name="sid" column="sid" type="int"> <generator class="native"/> </id> <property name="sname" column="sname" type="string"/> <component name="cardId" class="net.nw.vo.component.IdCard"> <property name="pid" column="pid" type="string"></property> <property name="province" type="string"></property> </component> </class> </hibernate-mapping>
一對一映射關係小結:
再看一個例子,好比web開發中最最多見的用戶表,裏面有聯繫方式和姓名:
實體細粒度模型
public class Tusers { private Integer id; private Name name; // 1.姓名 private Contact contact; // 2.聯繫方式 } public class Name { private String firstname; private String lastname; } public class Contact { private String address; private String email; private String telphone; }
粗粒度的數據庫模型
實體一對一關聯:假如數據庫中已經存在contact、name表,而且Contact、Name設計成實體類,則Tusers 類與Contact,Name類之間成爲一對一關聯關係。不然就是組件映射關係。
問題小結:
期間使用註解的時候出現了一些瑕疵: