Hibernate【映射】續篇
小編:管理員 378閱讀 2022.09.14
Java主要的類主要有兩種方式
- 組合關系,組合關系對應的就是組件映射
- 繼承關系,繼承關系對應的就是繼承映射
組件映射實際上就是將組合關系的數據映射成一張表,組件類和被包含的組件類映射成一張表
有的時候,兩個類的關系明顯不是繼承關系,但兩個類的親密程度很高,在一個類里邊需要用到另外一個類…那么就在類中定義一個變量來維護另一個類的關系,這種就叫組合關系!
需求:汽車和輪子。汽車需要用到輪子,但是輪子的爸爸不可能是汽車吧?
設計數據庫
這里寫圖片描述
設計實體Wheel.java
public class Wheel { private int count; private int size; public int getCount() { return count; } public void setCount(int count) { this.count = count; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } }復制
Car.java,使用變量維護Wheel
package zhongfucheng.aa; /** * Created by ozc on 2017/5/7. */ public class Car { private int id; private String name; private Wheel wheel; public Wheel getWheel() { return wheel; } public void setWheel(Wheel wheel) { this.wheel = wheel; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }復制映射表
使用了一個新標簽<component>,組件映射標簽。
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="zhongfucheng.aa" > <class name="Car" table="Car" > <!--映射主鍵--> <id name="id" column="id"> <generator class="native"></generator> </id> <!--映射普通字段--> <property name="name" column="name" ></property> <!-- 映射組件字段 --> <component name="wheel"> <property name="count"></property> <property name="size"></property> </component> </class> </hibernate-mapping>復制測試
package zhongfucheng.aa; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; /** * Created by ozc on 2017/5/6. */ public class App5 { public static void main(String[] args) { //創建對象 Wheel wheel = new Wheel(); Car car = new Car(); //設置屬性 wheel.setCount(43); wheel.setSize(22); car.setName("寶馬"); //維護關系 car.setWheel(wheel); //獲取加載配置管理類 Configuration configuration = new Configuration(); configuration.configure().addClass(Car.class); //創建Session工廠對象 SessionFactory factory = configuration.buildSessionFactory(); //得到Session對象 Session session = factory.openSession(); //使用Hibernate操作數據庫,都要開啟事務,得到事務對象 Transaction transaction = session.getTransaction(); //開啟事務 transaction.begin(); session.save(car); //提交事務 transaction.commit(); //關閉Session session.close(); } }復制

這里寫圖片描述
傳統方式繼承需求:動物、貓、猴子。貓繼承著動物
傳統方式繼承的特點就是:有多少個子類就寫多少個配置文件.
表結構我們的表應該是這樣的:id和name從Animal中繼承,catchMouse是子類的具體行為。

這里寫圖片描述
實體Animal.java
package zhongfucheng.aa; // 動物類 public abstract class Animal { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }復制
Cat.java繼承著Animail
package zhongfucheng.aa; public class Cat extends Animal{ // 抓老鼠 private String catchMouse; public String getCatchMouse() { return catchMouse; } public void setCatchMouse(String catchMouse) { this.catchMouse = catchMouse; } }復制
映射文件
簡單繼承的映射文件很好寫,在屬性上,直接寫父類的屬性就可以了。
但是也有致命的缺點:如果子類有很多,就需要寫很多的配置文件
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="zhongfucheng.aa" > <class name="Cat" table="cat" > <!--映射主鍵--> <id name="id" column="id"> <generator class="native"></generator> </id> <!-- 映射普通字段 父類的屬性直接引用就行了,比如name屬性,直接寫就行了! --> <property name="name" column="name" ></property> <property name="catchMouse" column="catchMouse" ></property> </class> </hibernate-mapping>復制測試
package zhongfucheng.aa; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class App5 { public static void main(String[] args) { //創建對象 Cat cat = new Cat(); //設置屬性 cat.setName("大花貓"); cat.setCatchMouse("捉大老鼠"); //獲取加載配置管理類 Configuration configuration = new Configuration(); configuration.configure().addClass(Cat.class); //創建Session工廠對象 SessionFactory factory = configuration.buildSessionFactory(); //得到Session對象 Session session = factory.openSession(); //使用Hibernate操作數據庫,都要開啟事務,得到事務對象 Transaction transaction = session.getTransaction(); //開啟事務 transaction.begin(); session.save(cat); //如果取數據時候Animal父類接收的話,需要給出Anmail的全名 //提交事務 transaction.commit(); //關閉Session session.close(); } }復制

這里寫圖片描述
把所有子類映射成一張表
前面我們采用的是:每個子類都需要寫成一個配置文件,映射成一張表…
如果子類的結構很簡單,只比父類多幾個屬性。就像上面的例子…我們可以將所有的子類都映射成一張表中
但是呢,這樣是不符合數據庫設計規范的…..因為表中的數據可能是貓,可能是猴子…這明顯是不合適的…
由于表中可能存在貓,存在猴子,為了區分是什么類型的。我們需要使用鑒別器
我們了解一下…
數據表
這里寫圖片描述
實體實體和上面雷同,只多了一個猴子的實體表
Monkey.java
public class Monkey extends Animal { // 吃香蕉 private String eatBanana; public String getEatBanana() { return eatBanana; } public void setEatBanana(String eatBanana) { this.eatBanana = eatBanana; } }復制映射文件
使用了subClass這個節點和鑒別器
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!-- 繼承映射, 所有的子類都映射到一張表 --> <hibernate-mapping package="cn.itcast.e_extends2"> <class name="Animal" table="t_animal"> <id name="id"> <generator class="native"></generator> </id> <!-- 指定鑒別器字段(區分不同的子類) --> <discriminator column="type_"></discriminator> <property name="name"></property> <!-- 子類:貓 每個子類都用subclass節點映射 注意:一定要指定鑒別器字段,否則報錯! 鑒別器字段:作用是在數據庫中區別每一個子類的信息, 就是一個列 discriminator-value="cat_" 指定鑒別器字段,即type_字段的值 如果不指定,默認為當前子類的全名 --> <subclass name="Cat" discriminator-value="cat_"> <property name="catchMouse"></property> </subclass> <!-- 子類:猴子 --> <subclass name="Monkey" discriminator-value="monkey_"> <property name="eatBanana"></property> </subclass> </class> </hibernate-mapping>復制測試
加載的是Animal父類的映射文件。保存的是cat和monkey。
package zhongfucheng.aa; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class App5 { public static void main(String[] args) { //創建對象 Cat cat = new Cat(); Monkey monkey = new Monkey(); //設置屬性 cat.setName("大花貓"); cat.setCatchMouse("小老鼠"); monkey.setEatBanana("吃香蕉"); monkey.setName("大猴子"); //獲取加載配置管理類 Configuration configuration = new Configuration(); //加載Animal的映射文件! configuration.configure().addClass(Animal.class); //創建Session工廠對象 SessionFactory factory = configuration.buildSessionFactory(); //得到Session對象 Session session = factory.openSession(); //使用Hibernate操作數據庫,都要開啟事務,得到事務對象 Transaction transaction = session.getTransaction(); //開啟事務 transaction.begin(); session.save(cat); session.save(monkey); //提交事務 transaction.commit(); //關閉Session session.close(); } }復制

這里寫圖片描述
每個類映射一張表(3張表)
父類和子類都各對應一張表。那么就有三張表了
這種結構看起來是完全面向對象,但是表之間的結構會很復雜,插入一條子類的信息,需要兩條SQL
數據表設計
這里寫圖片描述
映射文件使用到了<joined-subclass >這個節點
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="zhongfucheng.aa"> <class name="Animal" table="t_animal"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <!-- Animal下的子類映射成一張表 指定子類的類型,對應的表 指定子類的外鍵字段【需要對應Animal】 指定子類的普通屬性 --> <joined-subclass name="Cat" table="cat_"> <!--key對應的是外鍵字段--> <key column="animal_id"></key> <property name="catchMouse"></property> </joined-subclass> <joined-subclass name="Monkey" table="monkey_"> <!--key對應的是外鍵字段--> <key column="animal_id"></key> <property name="eatBanana"></property> </joined-subclass> </class> </hibernate-mapping>復制測試
package zhongfucheng.aa; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class App5 { public static void main(String[] args) { //創建對象 Cat cat = new Cat(); Monkey monkey = new Monkey(); //設置屬性 cat.setName("大花貓"); cat.setCatchMouse("小老鼠"); monkey.setEatBanana("吃香蕉"); monkey.setName("大猴子"); //獲取加載配置管理類 Configuration configuration = new Configuration(); //加載類對應的映射文件! configuration.configure().addClass(Animal.class); //創建Session工廠對象 SessionFactory factory = configuration.buildSessionFactory(); //得到Session對象 Session session = factory.openSession(); //使用Hibernate操作數據庫,都要開啟事務,得到事務對象 Transaction transaction = session.getTransaction(); //開啟事務 transaction.begin(); session.save(cat); session.save(monkey); //提交事務 transaction.commit(); //關閉Session session.close(); } }復制
每保存一個子類對象需要兩條SQL語句!

這里寫圖片描述
(推薦)每個子類映射一張表, 父類不對應表(2張表)
- 使用過了一張表保存所有子類的數據,這不符合數據庫設計規范
- 每個子類、父類都擁有一張表..表結構太過于繁瑣..添加信息時,過多的SQL
我們即將使用的是:每個子類映射成一張表,父類不對應表…這和我們傳統方式繼承是一樣的。只不過在hbm.xml文件中使用了<union-subclass>這個節點,由于有了這個節點,我們就不需要每個子類都寫一個配置文件了。
數據庫表設計
這里寫圖片描述
映射文件- 想要父類不映射成數據庫表,只要在class中配置為abstract即可
- 使用了union-subclass節點,主鍵就不能采用自動增長策略了。我們改成UUID即可。當然啦,對應的實體id類型要改成String
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="zhongfucheng.aa"> <!-- 想要父類不映射成表,設置成abstract --> <class name="Animal" abstract="true"> <!-- 如果使用了union-subclass節點,那么主鍵生成策略不能是自增長,我們改成uuid即可 --> <id name="id"> <generator class="uuid"></generator> </id> <property name="name"></property> <!-- 將子類的信息都映射成一張表 給出屬性的名稱 屬性對應的數據庫表 普通字段 --> <union-subclass name="Cat" table="cat_"> <property name="catchMouse"></property> </union-subclass> <union-subclass name="Monkey" table="monkey_"> <property name="eatBanana"></property> </union-subclass> </class> </hibernate-mapping>復制測試
package zhongfucheng.aa; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; public class App5 { public static void main(String[] args) { //創建對象 Cat cat = new Cat(); Monkey monkey = new Monkey(); //設置屬性 cat.setName("大花貓"); cat.setCatchMouse("小老鼠"); monkey.setEatBanana("吃香蕉"); monkey.setName("大猴子"); //獲取加載配置管理類 Configuration configuration = new Configuration(); //加載類對應的映射文件! configuration.configure().addClass(Animal.class); //創建Session工廠對象 SessionFactory factory = configuration.buildSessionFactory(); //得到Session對象 Session session = factory.openSession(); //使用Hibernate操作數據庫,都要開啟事務,得到事務對象 Transaction transaction = session.getTransaction(); //開啟事務 transaction.begin(); session.save(cat); session.save(monkey); //提交事務 transaction.commit(); //關閉Session session.close(); } }復制

這里寫圖片描述
組件映射和繼承映射總結由于我們的傳統繼承映射每個子類都對應一個配置文件,這樣十分麻煩。因此.hbm.xml就給出了幾個節點供我們使用,分別有以下的情況:
- 子類父類共有一張表subclass
- 不符合數據庫設計規范
- 需要使用鑒別器
- 子類、父類都有自己的表joined-subclass,那么就是三張表
- 表的結構太過繁瑣
- 插入數據時要生成SQL至少就要兩條
- 子類擁有自己的表、父類不對應表【推薦】union-subclass
- 父類不對應表要使用abstract來修飾
- 主鍵的id不能使用自增長策略,修改成UUID就好了。對應的JavaBean的id設置成String就好
相關推薦
- 經典筆試題-JDBC及Hibernate篇 五、JDBC 及Hibernate:(共12 題:基礎10 道,中等難度2 道)110、數據庫,比如100 用戶同時來訪,要采取什么技術解決?【基礎】 答:可采用連接池。111、什么是ORM?【基礎】 答:對象關系映射(Object—Relational Mapping,簡稱ORM)是一種為了解決面向對象…
- Hibernate Criterion 在查詢方法設計上能夠靈活的依據Criteria的特點來方便地進行查詢條件的組裝.Hibernate設計了CriteriaSpecification作為Criteria的父接口,以下提供了Criteria和DetachedCriteria.Criteria和DetachedCriteria的主要差別在于創建的形式不一樣,Criteria是在線的,所…