1.一對多、多對一、多對多的回顧
一對多: <set name="映射的集合屬性" table="(可選)集合屬性對應的外鍵表"> <key column="外鍵表的,外鍵字段" /> <one-to-many class="集合元素的類型" /> </set>多對一: <many-to-one name="對象屬性" class="對象類型" column="外鍵字段字段" />多對多 <set name="" table=""> <key column="" /> <many-to-many column="" class=""> </set>2.對象狀態a) Hibernate中持久化對象的狀態 瞬時/臨時狀態(Transient Objects) 使用new操作符初始化的對象不是立刻就持久化的,他們的狀態是瞬時的。 (1) 不處于session的緩存中,也可以說,不被任何一個Session實例關聯。 (2) 在數據庫中沒有對應的記錄。 持久化狀態(Persist Objects) 持久實例是任何具有數據庫標識的實例。它有持久化管理器Session統一管理,持久實例是在事務中進行操作的———他們的狀態在事務結束時同數據庫進行同步。(1) 位于一個Session實例的緩存中,也可以說,持久化對象總是被一個Session實例關聯。(2) 持久化對象和數據庫中的相關記錄對應。(3) Session在清理緩存時,會根據持久化對象的屬性變化,來同步更新數據庫。(4) 當調用session的save/saveOrUpdate/get/load/list等方法的時候,對象就是持久化狀態。處于持久化狀態的對象,當對對象屬性進行更改的時候,會反映到數據庫中!特點:處于session的管理;數據庫中有對應的記錄; 離線/游離對象(Detached Objects) Session關閉之后,持久化對象就變為離線對象。離線表示這個對象不能再與數據庫保持同步,他們不再受Hibernate管理。 (1) 不再位于Session的緩存中,也可以說,游離對象不被Session關聯。 (2) 游離對象是由持久化對象轉變過來的,因此在數據庫中可能還存在與它對應的記錄 (前提條件是沒有其他程序刪除了這條記錄)。 不處于session的管理;數據庫中有對應的記錄Session關閉后,對象的狀態;b) hibernate持久化對象的狀態轉換過程
/* * 臨時:對象不在session管理,與數據庫無對應的記錄 * 特點: * new出 * 持久:對象在session管理, 與數據庫有對應的記錄 * 特點: * 有oid * 對對象修改會同步到數據庫 * 游離:對象不在session管理,但與數據庫有對應的記錄. * 特點: * 修改對象,不會影響數據庫 */
Session session = SessionUtils.getSession();Transaction transaction = session.beginTransaction(); User user = (User) session.get(User.class, 1);user.setName(“jack”);user.setAge(30);user.setBirthday(new Date());transaction.commit();package com.xp.a_status;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.junit.Test;public class App1_status { PRivate static SessionFactory sf; static { sf = new Configuration().configure().addClass(User.class) // 測試時候使用 .buildSessionFactory(); } //1. 對象狀態的轉換 @Test public void testSaveSet() throws Exception { Session session = sf.openSession(); session.beginTransaction(); // 創建對象 【臨時狀態】 // User user = new User(); // user.setUserName("Jack22222"); // 保存 【持久化狀態】 // session.save(user); // user.setUserName("Jack333333"); // 會反映到數據庫 // 查詢 User user = (User) session.get(User.class, 5); user.setUserName("Tomcat"); // hibernate會自動與數據庫匹配(一級緩存),如果一樣就更新數據庫 session.getTransaction().commit(); session.close(); user.setUserName("Jack444444444"); // 打印 【游離狀態】 System.out.println(user.getUserId()); System.out.println(user.getUserName()); } @Test public void bak() throws Exception { Session session = sf.openSession(); session.beginTransaction(); session.getTransaction().commit(); session.close(); }}3. 一級緩存為什么要用緩存?目的:減少對數據庫的訪問次數!從而提升hibernate的執行效率!Hibernate中緩存分類:一級緩存二級緩存a) Hibernate3中Session緩存即一級緩存 Session緩存 Hibernate的一級緩存是由Session提供的,因此它存在于Session的整個生命周期中,當程序調用save()/update()/saveOrupdate()/get()等及查詢接口方法list()/iterator()方法時候,如果session中不存在該對象,那么會先將本次的對象存儲到一級緩存中便于以后使用,當Session關閉時同時清空一級緩存數據。clear()/evict() Session的緩存作用 減少訪問數據庫的次數,進而提高效率。保證緩存中的對象與數據庫的記錄保持 同步,當緩存的對象改變后,session不會立即執行sql,而是將多個sql語句合并 為一條sql進行執行,提高效率。 session的緩存舉例 當用戶需要對指定的對象進行修改的時候,如果對于同一個屬性修改了多次,其實hibernate的session緩存并不是執行多個update語句,而是以最后一個更新為準而發送一條更新的sql。b)hibernate中的session緩存問題Get()先將獲取的對象存儲到一級緩存,當再次加載同一個持久化對象的時候先檢測一級緩存中是否有該對象,如果有直接獲取,不會發送SQL語句,否則才發送SQLpublic void cache(){ Session session = SessionUtils.getCurrentSession(); session.beginTransaction(); Query query = null; DataType dataType = null; DataType dataType1 = null; try { // 獲取要修改的對象 dataType = (DataType) session.get(DataType.class, new Long(1)); // session.evict(dataType);和session.clear();方法會清理緩存 dataType1 = (DataType) session.get(DataType.class, new Long(1)); System.out.println(dataType == dataType1); session.getTransaction().commit(); } catch (Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } }public void cache(){ Session session = SessionUtils.getCurrentSession(); session.beginTransaction(); Query query = null; try { query = session.createQuery("from DataType"); List list = query.list(); System.out.println(list); // session.clear(); Iterator<DataType> it = query.iterate(); while(it.hasNext()){ System.out.println(it.next()); } session.getTransaction().commit(); } catch (Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } }List()查詢出來的結果會被緩存起來,那么當
terator()再查看的時候會先發送查詢id的SQL,
但是查詢實體的SQL不會發出,因為它首先回去一
級緩存中獲取已經緩存的數據。
D)緩存相關幾個方法的作用
session.flush(); 讓一級緩存與數據庫同步
session.evict(arg0); 清空一級緩存中指定的對象
session.clear(); 清空一級緩存中緩存的所有對象
在什么情況用上面方法?
批量操作使用使用:
Session.flush(); // 先與數據庫同步
Session.clear(); // 再清空一級緩存內容
1)Hibenate中一級緩存,也叫做session的緩存,它可以在session范圍內減少數據庫的訪問次數! 只在session范圍有效!Session關閉,一級緩存失效!
2)當調用session的save/saveOrUpdate/get/load/list/iterator方法的時候,都會把對象放入session的緩存中。
3)Session的緩存由hibernate維護, 用戶不能操作緩存內容; 如果想操作緩存內容,必須通過hibernate提供的evit/clear方法操作。
特點:
只在(當前)session范圍有效,作用時間短,效果不是特別明顯!
在短時間內多次操作數據庫,效果比較明顯!
面試題1: 不同的session是否會共享緩存數據?
不會。
Session session1=sessionFactory.openSession();Session session2=sessionFactory.openSession();Transaction tx1 = session1.beginTransaction(); Transaction tx2 = session2.beginTransaction();//Customer對象被session1關聯Customer c=(Customer)session1.get(Customer.class,new Long(1)); //Customer對象被session2關聯session2.update(c); c.setName("Jack"); //修改Customer對象的屬性tx1.commit(); //執行update語句 tx2.commit(); //執行update語句session1.close(); session2.close();當執行session1的load()方法時,OID為1的Customer對象被加入到session1的緩存中,因此它是session1的持久化對象,此時它還沒有被session2關聯,因此相對于session2,它處于游離狀態。當執行session2的update()方法時,Customer對象被加入到session2的緩存中,因此也成為session2的持久化對象。接下來修改Customer對象的name屬性,會導致兩個Session實例在清理各自的緩存時,都執行相同的update語句:update CUSTOMERS set NAME='Jack' …… where ID=1;? 面試題2: list與iterator查詢的區別?list() 一次把所有的記錄都查詢出來,會放入緩存,但不會從緩存中獲取數據 Iterator N+1查詢; N表示所有的記錄總數 即會先發送一條語句查詢所有記錄的主鍵(1),再根據每一個主鍵再去數據庫查詢(N)!會放入緩存,也會從緩存中取數據!package com.xp.a_status;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.junit.Test;public class App2_cache { private static SessionFactory sf; static { sf = new Configuration().configure().addClass(User.class) // 測試時候使用 .buildSessionFactory(); } @Test public void testCache() throws Exception { Session session = sf.openSession(); session.beginTransaction(); User user = null; // 查詢 user = (User) session.get(User.class, 5); // 先檢查緩存中是否有數據,如果有不查詢數據庫,直接從緩存中獲取 user = (User) session.get(User.class, 5); // 先檢查緩存中是否有數據,如果有不查詢數據庫,直接從緩存中獲取 session.getTransaction().commit(); session.close(); } @Test public void flush() throws Exception { Session session = sf.openSession(); session.beginTransaction(); User user = null; user = (User) session.get(User.class, 5); user.setUserName("Jack"); // 緩存數據與數據庫同步 session.flush(); user.setUserName("Jack_new"); session.getTransaction().commit(); // session.flush(); session.close(); } @Test public void clear() throws Exception { Session session = sf.openSession(); session.beginTransaction(); User user = null; // 查詢 user = (User) session.get(User.class, 5); // 清空緩存內容 // session.clear(); // 清空所有 session.evict(user); // 清除指定 user = (User) session.get(User.class, 5); session.getTransaction().commit(); // session.flush(); session.close(); } @Test public void sessionTest() throws Exception { Session session1 = sf.openSession(); session1.beginTransaction(); Session session2 = sf.openSession(); session2.beginTransaction(); // user放入session1的緩存區 User user = (User) session1.get(User.class, 1); // user放入session2的緩存區 session2.update(user); // 修改對象 user.setUserName("New Name"); // 2條update session1.getTransaction().commit(); // session1.flush(); session1.close(); session2.getTransaction().commit(); // session2.flush(); session2.close(); }}package com.xp.a_status;import java.util.Iterator;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.junit.Test;public class App3_list_iterator { private static SessionFactory sf; static { sf = new Configuration().configure().addClass(User.class) // 測試時候使用 .buildSessionFactory(); } /** * list與iterator區別 * 1. list 方法 * 2. iterator 方法 * 3. 緩存 * @throws Exception */ //1. list 方法 @Test public void list() throws Exception { Session session = sf.openSession(); session.beginTransaction(); // HQL查詢 Query q = session.createQuery("from User "); // list()方法 List<User> list = q.list(); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } session.getTransaction().commit(); session.close(); } //2. iterator 方法 @Test public void iterator() throws Exception { Session session = sf.openSession(); session.beginTransaction(); // HQL查詢 Query q = session.createQuery("from User "); // iterator()方法 Iterator<User> it = q.iterate(); while (it.hasNext()) { // 得到當前迭代的每一個對象 User user = it.next(); System.out.println(user); } session.getTransaction().commit(); session.close(); } //3. 緩存 @Test public void cache() throws Exception { Session session = sf.openSession(); session.beginTransaction(); /**************執行2次list***************** Query q = session.createQuery("from User"); List<User> list = q.list(); // 【會放入?】 for (int i=0; i<list.size(); i++){ System.out.println(list.get(i)); } System.out.println("=========list==========="); list = q.list(); // 【會放入?】 for (int i=0; i<list.size(); i++){ System.out.println(list.get(i)); } /**************執行2次iteator******************/ Query q = session.createQuery("from User "); Iterator<User> it = q.iterate(); // 【放入緩存】 while (it.hasNext()) { User user = it.next(); System.out.println(user); } System.out.println("==========iterate==========="); it = q.iterate(); // 【也會從緩存中取】 while (it.hasNext()) { User user = it.next(); System.out.println(user); } session.getTransaction().commit(); session.close(); } // 測試list方法會放入緩存 @Test public void list_iterator() throws Exception { Session session = sf.openSession(); session.beginTransaction(); // 得到Query接口的引用 Query q = session.createQuery("from User "); // 先list 【會放入緩存,但不會從緩存中獲取數據】 List<User> list = q.list(); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } // 再iteraotr (會從緩存中取) Iterator<User> it = q.iterate(); while (it.hasNext()) { User user = it.next(); System.out.println(user); } session.getTransaction().commit(); session.close(); }}4.懶加載
面試題3: get、load方法區別?get: 及時加載,只要調用get方法立刻向數據庫查詢load:默認使用懶加載,當用到數據的時候才向數據庫查詢。 懶加載:(lazy)概念:當用到數據的時候才向數據庫查詢,這就是hibernate的懶加載特性。目的:提供程序執行效率! lazy 值true 使用懶加載false 關閉懶加載extra (在集合數據懶加載時候提升效率)在真正使用數據的時候才向數據庫發送查詢的sql;如果調用集合的size()/isEmpty()方法,只是統計,不真正查詢數據! 懶加載異常 Session關閉后,不能使用懶加載數據! 如果session關閉后,使用懶加載數據報錯:org.hibernate.LazyInitializationException: could not initialize proxy - no Session如何解決session關閉后不能使用懶加載數據的問題? // 方式1: 先使用一下數據//dept.getDeptName();// 方式2:強迫代理對象初始化Hibernate.initialize(dept);// 方式3:關閉懶加載設置lazy=false;// 方式4: 在使用數據之后,再關閉session!
package com.xp.b_one2many;public class Employee { private int empId; private String empName; private double salary; // 【多對一】員工與部門 private Dept dept;; public int getEmpId() { return empId; } public void setEmpId(int empId) { this.empId = empId; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; }}<?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="com.xp.b_one2many"> <class name="Employee" table="t_employee"> <id name="empId"> <generator class="native"></generator> </id> <property name="empName" length="20"></property> <property name="salary" type="double"></property> <many-to-one name="dept" column="dept_id" class="Dept"></many-to-one> </class></hibernate-mapping>package com.xp.b_one2many;import java.util.HashSet;import java.util.Set;public class Dept { private int deptId; private String deptName; // 【一對多】 部門對應的多個員工 private Set<Employee> emps = new HashSet<Employee>(); public int getDeptId() { return deptId; } public void setDeptId(int deptId) { this.deptId = deptId; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public Set<Employee> getEmps() { return emps; } public void setEmps(Set<Employee> emps) { this.emps = emps; }}<?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="com.xp.b_one2many"> <class name="Dept" table="t_dept" > <id name="deptId"> <generator class="native"></generator> </id> <property name="deptName" length="20"></property> <!-- 集合屬性,默認使用懶加載 lazy true 懶加載 extra 懶加載(智能) false 關閉懶加載 --> <set name="emps" lazy="extra"> <key column="dept_id"></key> <one-to-many class="Employee"/> </set> </class></hibernate-mapping>package com.xp.b_one2many;import org.hibernate.Hibernate;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.junit.Test;public class App { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(Dept.class) .addClass(Employee.class) // 測試時候使用 .buildSessionFactory(); } //1. 主鍵查詢,及區別 @Test public void get_load() { Session session = sf.openSession(); session.beginTransaction(); Dept dept = new Dept(); // get: 及時查詢// dept = (Dept) session.get(Dept.class, 9);// System.out.println(dept.getDeptName()); // load,默認懶加載, 及在使用數據的時候,才向數據庫發送查詢的sql語句! dept = (Dept)session.load(Dept.class, 9); // 方式1: 先使用一下數據 //dept.getDeptName(); // 方式2:強迫代理對象初始化 Hibernate.initialize(dept); // 方式3:關閉懶加載 session.getTransaction().commit(); session.close(); // 在這里使用 System.out.println(dept.getDeptName()); } //1. 主鍵查詢,及區別 @Test public void set() { Session session = sf.openSession(); session.beginTransaction(); Dept dept = (Dept) session.get(Dept.class, 10); System.out.println(dept.getDeptName()); System.out.println("------"); System.out.println(dept.getEmps().isEmpty()); // SQL session.getTransaction().commit(); session.close(); }}5.一對一映射需求: 用戶與身份證信息 一條用戶記錄對應一條身份證信息! 一對一的關系!設計數據庫:JavaBean:映射:package com.xp.c_one2one;public class IdCard { // 身份證號(主鍵) private String cardNum;// 對象唯一表示(Object Identified, OID) private String place; // 身份證地址 // 身份證與用戶,一對一的關系 private User user; public String getCardNum() { return cardNum; } public void setCardNum(String cardNum) { this.cardNum = cardNum; } public String getPlace() { return place; } public void setPlace(String place) { this.place = place; } public User getUser() { return user; } public void setUser(User user) { this.user = user; }}<?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="com.xp.c_one2one"> <class name="IdCard" table="t_IdCard"> <id name="cardNum"> <generator class="assigned"></generator> </id> <property name="place" length="20"></property> <!-- 一對一映射,有外鍵方 unique="true" 給外鍵字段添加唯一約束 --> <many-to-one name="user" unique="true" column="user_id" class="User" cascade="save-update"></many-to-one> </class></hibernate-mapping>package com.xp.c_one2one;public class User { private int userId; private String userName; // 用戶與身份證信息, 一對一關系 private IdCard idCard; public IdCard getIdCard() { return idCard; } public void setIdCard(IdCard idCard) { this.idCard = idCard; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; }}<?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="com.xp.c_one2one"> <class name="User" table="t_user"> <id name="userId"> <generator class="native"></generator> </id> <property name="userName" length="20"></property> <!-- 一對一映射: 沒有外鍵方 --> <one-to-one name="idCard" class="IdCard"></one-to-one> </class></hibernate-mapping>package com.xp.c_one2one;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.junit.Test;public class App { private static SessionFactory sf; static { sf = new Configuration().configure().addClass(IdCard.class) .addClass(User.class) // 測試時候使用 .buildSessionFactory(); } @Test public void getSave() { Session session = sf.openSession(); session.beginTransaction(); // 用戶 User user = new User(); user.setUserName("Jack"); // 身份證 IdCard idCard = new IdCard(); idCard.setCardNum("441202XXX"); idCard.setPlace("廣州XXX"); // 關系 idCard.setUser(user); // ----保存---- session.save(idCard); session.getTransaction().commit(); session.close(); }}基于主鍵的映射// 身份證public class IdCard { private int user_id; // 身份證號 private String cardNum; private String place; // 身份證地址 // 身份證與用戶,一對一的關系 private User user; <?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.c_one2one2"> <class name="IdCard" table="t_IdCard"> <id name="user_id"> <!-- id 節點指定的是主鍵映射, 即user_id是主鍵 主鍵生成方式: foreign 即把別的表的主鍵作為當前表的主鍵; property (關鍵字不能修改)指定引用的對象 對象的全名 cn..User、 對象映射 cn.User.hbm.xml、 table(id) --> <generator class="foreign"> <param name="property">user</param> </generator> </id> <property name="cardNum" length="20"></property> <property name="place" length="20"></property> <!-- 一對一映射,有外鍵方 (基于主鍵的映射) constrained="true" 指定在主鍵上添加外鍵約束 --> <one-to-one name="user" class="User" constrained="true" cascade="save-update"></one-to-one> </class></hibernate-mapping>6.組件映射類組合關系的映射,也叫做組件映射!注意:組件類和被包含的組件類,共同映射到一張表!需求: 汽車與車輪數據庫 T_car 主鍵 汽車名稱 輪子大小 個數package com.xp.d_component;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; }}package com.xp.d_component;public class Car { private int id; private String name; // 車輪 private 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; } public Wheel getWheel() { return wheel; } public void setWheel(Wheel wheel) { this.wheel = wheel; }}<?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="com.xp.d_component"> <class name="Car" table="t_car"> <id name="id"> <generator class="native"></generator> </id> <property name="name" length="20"></property> <!-- 組件映射 --> <component name="wheel"> <property name="size"></property> <property name="count"></property> </component> </class></hibernate-mapping>package com.xp.d_component;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.junit.Test;public class App { private static SessionFactory sf; static { sf = new Configuration().configure().addClass(Car.class) .buildSessionFactory(); } @Test public void getSave() { Session session = sf.openSession(); session.beginTransaction(); // 輪子 Wheel wheel = new Wheel(); wheel.setSize(38); wheel.setCount(4); // 汽車 Car car = new Car(); car.setName("BMW"); car.setWheel(wheel); // 保存 session.save(car); session.getTransaction().commit(); session.close(); }}7.繼承映射需求:動物貓猴子動物類public class Animal { private int id; private String name;}package com.xp.e_extends1;public class Cat extends Animal{ // 抓老鼠 private String catchMouse; public String getCatchMouse() { return catchMouse; } public void setCatchMouse(String catchMouse) { this.catchMouse = catchMouse; }}package com.xp.e_extends1;public class Monkey { // 吃香蕉 private String eatBanana;}<?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="com.xp.e_extends1"> <class name="Cat" table="t_Cat"> <!-- 簡單繼承映射: 父類屬性直接寫 --> <id name="id"> <generator class="native"/> </id> <property generated="never" lazy="false" name="name"/> <property generated="never" lazy="false" name="catchMouse"/> </class></hibernate-mapping> package com.xp.e_extends1;import org.hibernate.Query;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.hibernate.classic.Session;import org.junit.Test;import java.util.List;public class App { private static SessionFactory sf; static { sf = new Configuration().configure().addClass(Cat.class) .buildSessionFactory(); } @Test public void getSave() { Session session = sf.openSession(); session.beginTransaction(); // 保存 // Cat cat = new Cat(); // cat.setName("大花貓"); // cat.setCatchMouse("抓小老鼠"); // session.save(cat); // 獲取時候注意:當寫hql查詢的使用,通過父類查詢必須寫上類的全名 Query q = session.createQuery("from cn.itcast.e_extends1.Animal"); List<Animal> list = q.list(); System.out.println(list); session.getTransaction().commit(); session.close(); }} 簡單繼承映射,有多少個子類,寫多少個映射文件!8.繼承映射2需求:貓、猴子、動物。所有子類映射到一張表 (1張表)什么情況用? 子類教多,且子類較為簡單,即只有個別屬性! 好處:因為使用一個映射文件, 減少了映射文件的個數。 缺點:(不符合數據庫設計原則)一個映射文件: Animal.hbm.xml (如何區分是哪個子類的信息?)數據庫: T_animal (要存儲所有的子類信息) “鑒別器” Id name catchMouse eatBanana type_(區別是哪個子類) 1 大馬猴 NULL 吃10個香蕉 猴子 2 大花貓 不抓老鼠 NULL 貓package com.xp.e_extends2;public 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; }}<?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="com.xp.e_extends2"> <class name="Animal" table="t_animal"> <id name="id"> <generator class="native"/> </id> <discriminator column="type_" force="false" insert="true" not-null="true"/> <property generated="never" lazy="false" name="name"/> <!-- 子類:貓 每個子類都用subclass節點映射 注意:一定要指定鑒別器字段,否則報錯! 鑒別器字段:作用是在數據庫中區別每一個子類的信息, 就是一個列 discriminator-value="cat_" 指定鑒別器字段,即type_字段的值 如果不指定,默認為當前子類的全名 --> <subclass discriminator-value="cat_" name="Cat" select-before-update="false"> <property generated="never" lazy="false" name="catchMouse"/> </subclass> <!-- 子類:猴子 --> <subclass discriminator-value="monkey_" name="Monkey" select-before-update="false"> <property generated="never" lazy="false" name="eatBanana"/> </subclass> </class></hibernate-mapping>package com.xp.e_extends2;public class Monkey extends Animal{ // 吃香蕉 private String eatBanana; public String getEatBanana() { return eatBanana; } public void setEatBanana(String eatBanana) { this.eatBanana = eatBanana; }}package com.xp.e_extends2;public class Cat extends Animal{ // 抓老鼠 private String catchMouse; public String getCatchMouse() { return catchMouse; } public void setCatchMouse(String catchMouse) { this.catchMouse = catchMouse; }}package com.xp.e_extends2;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;import org.hibernate.classic.Session;import org.junit.Test;public class App { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(Animal.class) .buildSessionFactory(); } @Test public void getSave() { Session session = sf.openSession(); session.beginTransaction(); // 保存 Cat cat = new Cat(); cat.setName("大花貓"); cat.setCatchMouse("抓小老鼠"); Monkey m = new Monkey(); m.setName("猴子"); m.setEatBanana("吃10個香蕉"); // 保存 session.save(cat); session.save(m); session.getTransaction().commit(); session.close(); }}總結: 寫法較為簡單:所有子類用一個映射文件,且映射到一張表! 但數據庫設計不合理! (不推薦用。)每個類映射一張表(3張表)數據庫 T_anmal (存儲父類信息) 1 大花貓 T_cat (引用父類的主鍵) 1 抓小老鼠T_monkey(引用父類的主鍵)Javabean設計一樣,映射實現不同:<!-- 繼承映射, 每個類對應一張表(父類也對應表) --><hibernate-mapping package="cn.itcast.e_extends3"> <class name="Animal" table="t_animal"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <!-- 子類:貓 t_cat key 指定_cat表的外鍵字段 --> <joined-subclass name="Cat" table="t_cat"> <key column="t_animal_id"></key> <property name="catchMouse"></property> </joined-subclass> <!-- 子類:猴子 t_monkey --> <joined-subclass name="Monkey" table="t_monkey"> <key column="t_animal_id"></key> <property name="eatBanana"></property> </joined-subclass> </class> </hibernate-mapping>總結: 一個映射文件,存儲所有的子類; 子類父類都對應表; 缺點:表結構比較負責,插入一條子類信息,需要用2條sql: 往父類插入、往子類插入!(推薦)每個子類映射一張表, 父類不對應表(2張表)數據庫: T_cat Id name catchMounse T_monkey Id name eatBanana<union-subclass name="Cat" table="t_cat"> <property name="catchMouse"></property> </union-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="com.xp.e_extends3"> <class name="Animal" table="t_animal"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <!-- 子類:貓 t_cat key 指定_cat表的外鍵字段 --> <joined-subclass name="Cat" table="t_cat"> <key column="t_animal_id"></key> <property name="catchMouse"></property> </joined-subclass> <!-- 子類:猴子 t_monkey --> <joined-subclass name="Monkey" table="t_monkey"> <key column="t_animal_id"></key> <property name="eatBanana"></property> </joined-subclass> </class></hibernate-mapping>或<?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_extends4"> <!-- abstract="true" 指定實體類對象不對應表,即在數據庫段不生成表 --> <class name="Animal" abstract="true"> <!-- 如果用union-subclass節點,主鍵生成策略不能為自增長! --> <id name="id"> <generator class="uuid"></generator> </id> <property name="name"></property> <!-- 子類:貓 t_cat union-subclass table 指定為表名, 表的主鍵即為id列 --> <union-subclass name="Cat" table="t_cat"> <property name="catchMouse"></property> </union-subclass> <!-- 子類:猴子 t_monkey --> <union-subclass name="Monkey" table="t_monkey"> <property name="eatBanana"></property> </union-subclass> </class></hibernate-mapping>Hibernate中映射: 多對一 一對多 多對多 一對一 (多對一的特殊應用) 組件 繼承
新聞熱點
疑難解答