日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

hibernate 继承映射

發布時間:2025/6/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hibernate 继承映射 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在域模型中,類與類之間除了關聯關系和聚集關系,還可以存在繼承關系,在下圖所示的域模型中,Deparment類和Employee類之間為一對多的雙向關聯關系,Employee類有兩個子類:Skiller類和Sales類。由于Java只允許一個類最多有一個直接的父類,因此Employee類、 Skiller類和Sales類構成了一棵繼承關系樹。

?在面向對象的范疇中,還存在多態的概念,多態建立在繼承關系的基礎上。簡單地理解,多態是指當一個Java應用變量被聲明為Employee類時,這個變量實際上既可以引用Employee類自己的實例,Skiller類的實例,也可以引用Sales類的實例。Department類的getEmps()方法通過HibernateAPI從數據庫中檢索出所有Employee對象。getEmps()方法返回的集合既可以包含Employee類自己的實例,Skiller類的實例,也可以引用Sales類的實例。,這種查詢被稱為多態查詢。數據庫表之間并不存在繼承關系,那么如何把域模型的繼承關系映射到關系數據模型中呢?hibernate有以下三種映射方式:

繼承關系樹的根類對應一個表:對關系數據模型進行非常規設計,在數據庫表中加入額外的區分子類型的字段。通過這種方式,可以使關系數據模型支持繼承關系和多態。

繼承關系樹的每個類對應一個表(子類與父類通過外鍵關聯):在關系數據模型中用外鍵參照關系來表示繼承關系。

繼承關系樹的每個具體類對應一個表:關系數據模型完全不支持域模型中的繼承關系和多態。

1.繼承關系樹的根類對應一個表employee(整個繼承樹一張表):

employee的表結構如下所示:

mysql> desc employee;
+------------+--------------+------+-----+---------+----------------+
| Field????? | Type???????? | Null | Key | Default | Extra????????? |
+------------+--------------+------+-----+---------+----------------+
| id???????? | int(11)????? | NO?? | PRI | NULL??? | auto_increment |
| type?????? | int(11)????? | NO?? |???? | NULL??? |??????????????? |
| name?????? | varchar(255) | YES? | UNI | NULL??? |??????????????? |
| depart_id? | int(11)????? | YES? | MUL | NULL??? |??????????????? |
| skill????? | varchar(255) | YES? |???? | NULL??? |??????????????? |
| saleAmount | int(11)????? | YES? |???? | NULL??? |??????????????? |
+------------+--------------+------+-----+---------+----------------+

實體類Department和Employee請參看我前面的文章,Skiller和Sales分別如下所示:

Java代碼 ?
  • package?com.reiyen.hibernate.domain;??
  • ??
  • public?class?Skiller?extends?Employee?{??
  • ??
  • ????private?String?skill;??
  • //setter和getter方法??
  • }??
  • ? Java代碼 ?
  • package?com.reiyen.hibernate.domain;??
  • public?class?Sales?extends?Employee?{??
  • ??
  • ????private?int?saleAmount;??
  • //setter和getter方法??
  • }??
  • ?Employee.hbm.xml映射文件如下:

    Xml代碼 ?
  • <?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?package="com.reiyen.hibernate.domain">??
  • ????<class?name="Employee"?discriminator-value="0">??
  • ????????<id?name="id">??
  • ????????????<generator?class="native"?/>??
  • ????????</id>??
  • ????????<!--discriminator(鑒別器):缺省類型為string,這里指定為int類型?-->??
  • ????????<discriminator?column="type"?type="int"></discriminator>??
  • ????????<property?name="name"?unique="true"/>??
  • ????????<!--?name="department"?這個名稱必須與Employee中的屬性名一致.?設置了column="depart_id",默認它會去department中找id與depart_id值相等的對象.如果要找name的值與depart_id相等的對象,則可以設置property-ref="name"?--&gt;??
  • ????????<many-to-one?name="department"?column="depart_id"?/>??
  • ????????<subclass?name="Skiller"?discriminator-value="1">??
  • ????????????<property?name="skill"?/>??
  • ????????</subclass>??
  • ????????<subclass?name="Sales"?discriminator-value="2">??
  • ????????????<property?name="saleAmount"?/>??
  • ????????</subclass>??
  • ????</class>??
  • </hibernate-mapping>??
  • ?

    ?測試類如下:

    Java代碼 ?
  • public?class?Many2One?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????add();??
  • ?????????query(1);//1??
  • ????}??
  • ??
  • ????static?void?query(int?empId)?{??
  • ????????Session?s?=?null;??
  • ????????Transaction?tx?=?null;??
  • ????????try?{??
  • ????????????s?=?HibernateUtil.getSession();??
  • ????????????tx?=?s.beginTransaction();??
  • ????????????Employee?emp?=?(Employee)?s.get(Employee.class,?empId);//2??
  • ????????????System.out.println(emp.getClass());??
  • ????????????tx.commit();??
  • ????????}?finally?{??
  • ????????????if?(s?!=?null)??
  • ????????????????s.close();??
  • ????????}??
  • ????}??
  • ??
  • ??
  • ??
  • ????static?void?add()?{??
  • ????????Session?s?=?null;??
  • ????????Transaction?tx?=?null;??
  • ????????try?{??
  • ????????????Department?depart?=?new?Department();??
  • ????????????depart.setName("department?name");??
  • ??????????????
  • ????????????Employee?employee1?=?new?Employee();??
  • ????????????employee1.setDepartment(depart);?//1?對象模型:建立兩個對象的關聯???
  • ????????????employee1.setName("employee1?name1");??
  • ??????????????
  • ????????????Skiller?employee2?=?new?Skiller();??
  • ????????????employee2.setDepartment(depart);?//2?對象模型:建立兩個對象的關聯???
  • ????????????employee2.setName("employee2?name2");??
  • ????????????employee2.setSkill("j2se");??
  • ??????????????
  • ????????????Sales?employee3?=?new?Sales();??
  • ????????????employee3.setDepartment(depart);?//2?對象模型:建立兩個對象的關聯???
  • ????????????employee3.setName("employee3?name3");??
  • ????????????employee3.setSaleAmount(1000);??
  • ??????????????
  • ????????????s?=?HibernateUtil.getSession();??
  • ????????????tx?=?s.beginTransaction();??
  • ????????????s.save(depart);??
  • ????????????s.save(employee1);??
  • ????????????s.save(employee2);??
  • ????????????s.save(employee3);??
  • ????????????tx.commit();??
  • ????????}?finally?{??
  • ????????????if?(s?!=?null)??
  • ????????????????s.close();??
  • ????????}??
  • ????}??
  • }??
  • ?程序運行后,控制臺打印信息如下所示:

    Hibernate: insert into Department (name) values (?)
    Hibernate: insert into Employee (name, depart_id, type) values (?, ?, 0)
    Hibernate: insert into Employee (name, depart_id, skill, type) values (?, ?, ?, 1)
    Hibernate: insert into Employee (name, depart_id, saleAmount, type) values (?, ?, ?, 2)
    Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_,employee0_.depart_id as depart4_1_0_, employee0_.skill as skill1_0_,employee0_.saleAmount as saleAmount1_0_, employee0_.type as type1_0_from Employee employee0_ where employee0_.id=?
    class com.reiyen.hibernate.domain.Employee

    employee表中記錄如下所示:

    mysql> select * from employee;
    +----+------+-----------------+-----------+-------+------------+
    | id | type | name??????????? | depart_id | skill | saleAmount |
    +----+------+-----------------+-----------+-------+------------+
    |? 1 |??? 0 | employee1 name1 |???????? 1 | NULL? |?????? NULL |
    |? 2 |??? 1 | employee2 name2 |???????? 1 | j2se? |?????? NULL |
    |? 3 |??? 2 | employee3 name3 |???? ? ? 1 | NULL? |?????? 1000 |
    +----+------+-----------------+-----------+-------+------------+
    3 rows in set (0.00 sec)

    將測試代碼中注釋為1的語句改成:

    Java代碼 ?
  • query(2);??
  • 再運行,控制臺打印的class如下所示(因為hibernate支持多態查詢): class com.reiyen.hibernate.domain.Skiller

    打印的查詢語句還是如上面所示的沒有改變。

    在上面修改的基礎上,再將測試代碼中注釋為2的語句改成:

    Java代碼 ?
  • Employee?emp?=?(Employee)?s.get(Skiller.class,?empId);??
  • ?再運行,則控制臺打印的查詢語句為:

    Hibernate: select skiller0_.id as id1_0_,skiller0_.name as name1_0_, skiller0_.depart_id as depart4_1_0_,skiller0_.skill as skill1_0_ from Employee skiller0_ where skiller0_.id=? and skiller0_.type=1
    class com.reiyen.hibernate.domain.Skiller

    優點:操作效率高

    缺點:如果說給employee增加子類的話,必須修改表結構,給表結構增加一個字段;同時表中對應子類的字段不能有非空約束.

    2.繼承關系樹的每子類對應一個表(joined-subclass),表結構如下所示:



    ?修改Employee.hbm.xml映射文件如下所示:

    Xml代碼 ?
  • <?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?package="com.reiyen.hibernate.domain">??
  • ????<class?name="Employee">??
  • ????????<id?name="id">??
  • ????????????<generator?class="native"?/>??
  • ????????</id>??
  • ????????<property?name="name"?unique="true"/>??
  • ????????<!--?name="department"?這個名稱必須與Employee中的屬性名一致.?設置了column="depart_id",默認它會去department中找id與depart_id值相等的對象.如果要找name的值與depart_id相等的對象,則可以設置property-ref="name"?--&gt;??
  • ????????<many-to-one?name="department"?column="depart_id"?/>??
  • ????????<joined-subclass?name="Skiller"?table="skiller">??
  • ?????????<key?column="employee_id"?/>??
  • ?????????<property?name="skill"?/>??
  • ????????</joined-subclass>??
  • ????????<joined-subclass?name="Sales"?table="sales">??
  • ?????????<key?column="employee_id"?/>??
  • ?????????<property?name="saleAmount"?column="sale_amount"?/>??
  • ????????</joined-subclass>??
  • ????</class>??
  • </hibernate-mapping>??
  • ?測試類不變,只是將測試代碼中注釋為1的語句改成:

    Java代碼 ?
  • query(2);??
  • 則控制臺打印的信息如下所示:

    Hibernate: insert into Department (name) values (?)
    Hibernate: insert into Employee (name, depart_id) values (?, ?)
    Hibernate: insert into Employee (name, depart_id) values (?, ?)
    Hibernate: insert into skiller (skill, employee_id) values (?, ?)

    Hibernate: insert into Employee (name, depart_id) values (?, ?)
    Hibernate: insert into sales (sale_amount, employee_id) values (?, ?)
    Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart3_1_0_, employee0_1_.skill as skill2_0_, employee0_2_.sale_amount as sale2_3_0_, case when employee0_1_.employee_id is not null then 1 when employee0_2_.employee_id is not null then 2 when employee0_.id is not null then 0 end as clazz_0_ from Employee employee0_ left outer join skiller employee0_1_ on employee0_.id=employee0_1_.employee_id left outer join sales employee0_2_ on employee0_.id=employee0_2_.employee_id where employee0_.id=?
    class com.reiyen.hibernate.domain.Skiller
    ?從打印的SQL語句可以看出,此時,如果保存的是Employee對象的子類的實例的話,則要在兩張表中保存記錄;如果查詢的是子類對象的話,是三張表關聯在一起進行查詢。

    ?

    在上面修改的基礎上,再將測試代碼中注釋為2的語句改成:

    Java代碼 ?
  • Employee?emp?=?(Employee)?s.get(Skiller.class,?empId);??
  • ?再運行,則控制臺打印的查詢語句為:

    Hibernate: select skiller0_.employee_id as id1_0_, skiller0_1_.name as name1_0_, skiller0_1_.depart_id as depart3_1_0_, skiller0_.skill as skill2_0_ from skiller skiller0_ inner join Employee skiller0_1_ on skiller0_.employee_id=skiller0_1_.id where skiller0_.employee_id=?
    此時只關聯兩張表查詢。

    數據庫中表記錄如下所示:

    mysql> select * from employee;
    +----+-----------------+-----------+
    | id | name??????????? | depart_id |
    +----+-----------------+-----------+
    |? 1 | employee1 name1 |???????? 1 |
    |? 2 | employee2 name2 |???????? 1 |
    |? 3 | employee3 name3 |???????? 1 |
    +----+-----------------+-----------+
    3 rows in set (0.00 sec)

    mysql> select * from skiller;
    +-------------+-------+
    | employee_id | skill |
    +-------------+-------+
    |?????????? 2 | j2se? |
    +-------------+-------+
    1 row in set (0.00 sec)

    mysql> select * from sales;
    +-------------+-------------+
    | employee_id | sale_amount |
    +-------------+-------------+
    |?????????? 3 |??????? 1000 |
    +-------------+-------------+
    1 row in set (0.00 sec)

    ?

    3.混合使用,假設如果Sales的屬性很多,而Skiller的屬性很少,這時可以混使用“一個類繼承體系一張表”和“每個子類一張表”,表結構如下所示:



    ?Employee.hbm.xml映射文件如下所示:

    Xml代碼 ?
  • <?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?package="com.reiyen.hibernate.domain">??
  • ????<class?name="Employee"?discriminator-value="0">??
  • ????????<id?name="id">??
  • ????????????<generator?class="native"?/>??
  • ????????</id>??
  • ????????<discriminator?column="type"?type="int"?/>??
  • ????????<property?name="name"?unique="true"?/>??
  • ????????<!--?name="department"?這個名稱必須與Employee中的屬性名一致.?設置了column="depart_id",默認它會去department中找id與depart_id值相等的對象.如果要找name的值與depart_id相等的對象,則可以設置property-ref="name"?--&gt;??
  • ????????<many-to-one?name="department"?column="depart_id"?/>??
  • <!--如果discriminator-value沒有顯式的給定值的話,則與name屬性的值保持一致,即為Skiller?-->????????
  • <subclass?name="Skiller"?discriminator-value="1">??
  • ????????????<property?name="skill"?/>??
  • ????????</subclass>??
  • ????????<subclass?name="Sales"?discriminator-value="2">??
  • ????????????<join?table="sales">??
  • ????????????????<key?column="employee_id"?/>??
  • ????????????????<property?name="saleAmount"?column="sale_amount"?/>??
  • ????????????</join>??
  • ????????</subclass>??
  • ????</class>??
  • </hibernate-mapping>??
  • ?此時測試類不變,只是將測試代碼中注釋為1的語句改成:

    Java代碼 ?
  • query(2);??
  • 然后在上面的基礎上運行原程序,則控制臺會打印出如下異常信息:

    Hibernate: insert into Department (name) values (?)
    Hibernate: insert into Employee (name, depart_id, type) values (?, ?, 0)
    Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not insert: [com.reiyen.hibernate.domain.Employee]

    Caused by: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column 'type' in 'field list'

    這是因為我在hibernate.cfg.xml配置文件中配置了此項:

    Xml代碼 ?
  • <property?name="hbm2ddl.auto">create</property>??
  • ?所以在此次程序運行時,會刪除數據庫中的employee表,sales表,而employee表中有skiller表的外鍵關聯,所以不能刪除employee數據表了,所以拋出了上面的異常。此時你再查看數據庫表,如下所示 :

    mysql> select * from employee;
    +----+-----------------+-----------+
    | id | name??????????? | depart_id |
    +----+-----------------+-----------+
    |? 1 | employee1 name1 |???????? 1 |
    |? 2 | employee2 name2 |???????? 1 |
    |? 3 | employee3 name3 |???????? 1 |
    +----+-----------------+-----------+
    3 rows in set (0.00 sec)

    mysql> select * from skiller;
    +-------------+-------+
    | employee_id | skill |
    +-------------+-------+
    |?????????? 2 | j2se? |
    +-------------+-------+
    1 row in set (0.00 sec)

    mysql> select * from sales;
    Empty set (0.00 sec)

    所以得先手動刪除skiller數據表,然后再來運行程序:

    ?

    如果Employee.hbm.xml配置文件中

    Xml代碼 ?
  • <subclass?name="Skiller"?>??
  • 不配置discriminator-value="1",則會拋出如下異常:

    java.lang.ExceptionInInitializerError

    Caused by: org.hibernate.MappingException: Could not format discriminator value to SQL string

    因為如果discriminator-value沒有顯式的給定值的話,則與name屬性的值保持一致,即為Skiller ,所以會拋出如上異常!

    ?

    4.繼承關系樹的每個具體類對應一個表(union-subclass)

    表結構如下所示:


    Employee.hbm.xml映射文件如下:

    Xml代碼 ?
  • <?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?package="com.reiyen.hibernate.domain">??
  • ????<class?name="Employee">??
  • ????????<id?name="id">??
  • ????????????<generator?class="hilo"?/>??
  • ????????</id>??
  • ????????<property?name="name"?unique="true"?/>??
  • ????????<many-to-one?name="department"?column="depart_id"?/>??
  • ????????<union-subclass?name="Skiller"?table="skiller">??
  • ?????????<property?name="skill"?/>??
  • ????????</union-subclass>??
  • ????????<union-subclass?name="Sales"?table="sales">??
  • ?????????<property?name="saleAmount"?column="sale_amount"?/>??
  • ????????</union-subclass>??
  • ????</class>??
  • </hibernate-mapping>??
  • ?此時主鍵增長不能再是:

    Xml代碼 ?
  • <generator?class="native"?/>??
  • 因為如果使用native的話三張表會產生相同的id值,這樣當根據id查詢Employee時就會出錯了。所以如果你配置成native時會拋出如下異常(因為Employee實體類中id對應 的是int了,所以在此使用hilo(高低位)主鍵生成方式):

    org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: com.reiyen.hibernate.domain.Skiller

    ?

    運行測試程序后,此時控制臺打印信息如下所示:

    Hibernate: insert into Department (name) values (?)
    Hibernate: insert into Employee (name, depart_id, id) values (?, ?, ?)
    Hibernate: insert into skiller (name, depart_id, skill, id) values (?, ?, ?, ?)
    Hibernate: insert into sales (name, depart_id, sale_amount, id) values (?, ?, ?, ?)
    Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart3_1_0_, employee0_.skill as skill2_0_, employee0_.sale_amount as sale1_3_0_, employee0_.clazz_ as clazz_0_ from ( select id, null as sale_amount, depart_id, null as skill, name, 0 as clazz_ from Employee union select id, null as sale_amount, depart_id, skill, name, 1 as clazz_ from skiller union select id, sale_amount, depart_id, null as skill, name, 2 as clazz_ from sales ) employee0_ where employee0_.id=?
    class com.reiyen.hibernate.domain.Skiller

    執行查詢時,首先使用子查詢,在子查詢中使用union將三張表的結果全成一張表,然后再在合成的結果集中進行查詢。

    如果Employee是一個抽象類,你不想在數據表中對應相應的數據表,則可以設置abstract="true".如下所示:

    Xml代碼 ?
  • <class?name="Employee"?abstract="true"?>??
  • ? 此外,如果繼承關系中有接口,可以把它當作抽象類對待。

    三種映射方式的比較和選擇
    為了方便說明為三種方式按順序標號為[1]整個繼承樹一張表;[2]每子類對應一個表(joined-subclass);[4]每個具體類對應一個表(union-subclass)。
    1、復雜度:

    ??? [1]簡單;
    ??? [2]表較多且之間有外鍵約束;

    ??? [4]包含重復字段;
    2、查詢性能:

    ??? [1]效率高;
    ??? [2]需要表內連接或左外連接;

    ??? [4]若查詢父類需查所有子類表;
    3、可維護性:

    ??? [1]只需修改一個表;
    ??? [2]若某個類屬性變化只修改這個類對應的表;

    ??? [4]若父類屬性變化需要修改所有子類對應的表;
    綜上,選擇時,可以參考以下原則:
    1、子類屬性不是非常多時,優先考慮[1],因為其性能最佳。
    2、子類屬性非常多,且對性能要求不是很嚴格時,優先考慮[2]

    總結

    以上是生活随笔為你收集整理的hibernate 继承映射的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。