1.一對多、多對一、多對多的回顧
一對多: <set name="映射的集合屬性" table="(可選)集合屬性對應(yīng)的外鍵表"> <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.對象狀態(tài)a) Hibernate中持久化對象的狀態(tài) 瞬時(shí)/臨時(shí)狀態(tài)(Transient Objects) 使用new操作符初始化的對象不是立刻就持久化的,他們的狀態(tài)是瞬時(shí)的。 (1) 不處于session的緩存中,也可以說,不被任何一個(gè)Session實(shí)例關(guān)聯(lián)。 (2) 在數(shù)據(jù)庫中沒有對應(yīng)的記錄。 持久化狀態(tài)(Persist Objects) 持久實(shí)例是任何具有數(shù)據(jù)庫標(biāo)識的實(shí)例。它有持久化管理器Session統(tǒng)一管理,持久實(shí)例是在事務(wù)中進(jìn)行操作的———他們的狀態(tài)在事務(wù)結(jié)束時(shí)同數(shù)據(jù)庫進(jìn)行同步。(1) 位于一個(gè)Session實(shí)例的緩存中,也可以說,持久化對象總是被一個(gè)Session實(shí)例關(guān)聯(lián)。(2) 持久化對象和數(shù)據(jù)庫中的相關(guān)記錄對應(yīng)。(3) Session在清理緩存時(shí),會根據(jù)持久化對象的屬性變化,來同步更新數(shù)據(jù)庫。(4) 當(dāng)調(diào)用session的save/saveOrUpdate/get/load/list等方法的時(shí)候,對象就是持久化狀態(tài)。處于持久化狀態(tài)的對象,當(dāng)對對象屬性進(jìn)行更改的時(shí)候,會反映到數(shù)據(jù)庫中!特點(diǎn):處于session的管理;數(shù)據(jù)庫中有對應(yīng)的記錄; 離線/游離對象(Detached Objects) Session關(guān)閉之后,持久化對象就變?yōu)殡x線對象。離線表示這個(gè)對象不能再與數(shù)據(jù)庫保持同步,他們不再受Hibernate管理。 (1) 不再位于Session的緩存中,也可以說,游離對象不被Session關(guān)聯(lián)。 (2) 游離對象是由持久化對象轉(zhuǎn)變過來的,因此在數(shù)據(jù)庫中可能還存在與它對應(yīng)的記錄 (前提條件是沒有其他程序刪除了這條記錄)。 不處于session的管理;數(shù)據(jù)庫中有對應(yīng)的記錄Session關(guān)閉后,對象的狀態(tài);b) hibernate持久化對象的狀態(tài)轉(zhuǎn)換過程
/* * 臨時(shí):對象不在session管理,與數(shù)據(jù)庫無對應(yīng)的記錄 * 特點(diǎn): * new出 * 持久:對象在session管理, 與數(shù)據(jù)庫有對應(yīng)的記錄 * 特點(diǎn): * 有oid * 對對象修改會同步到數(shù)據(jù)庫 * 游離:對象不在session管理,但與數(shù)據(jù)庫有對應(yīng)的記錄. * 特點(diǎn): * 修改對象,不會影響數(shù)據(jù)庫 */
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) // 測試時(shí)候使用 .buildSessionFactory(); } //1. 對象狀態(tài)的轉(zhuǎn)換 @Test public void testSaveSet() throws Exception { Session session = sf.openSession(); session.beginTransaction(); // 創(chuàng)建對象 【臨時(shí)狀態(tài)】 // User user = new User(); // user.setUserName("Jack22222"); // 保存 【持久化狀態(tài)】 // session.save(user); // user.setUserName("Jack333333"); // 會反映到數(shù)據(jù)庫 // 查詢 User user = (User) session.get(User.class, 5); user.setUserName("Tomcat"); // hibernate會自動(dòng)與數(shù)據(jù)庫匹配(一級緩存),如果一樣就更新數(shù)據(jù)庫 session.getTransaction().commit(); session.close(); user.setUserName("Jack444444444"); // 打印 【游離狀態(tài)】 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. 一級緩存為什么要用緩存?目的:減少對數(shù)據(jù)庫的訪問次數(shù)!從而提升hibernate的執(zhí)行效率!Hibernate中緩存分類:一級緩存二級緩存a) Hibernate3中Session緩存即一級緩存 Session緩存 Hibernate的一級緩存是由Session提供的,因此它存在于Session的整個(gè)生命周期中,當(dāng)程序調(diào)用save()/update()/saveOrupdate()/get()等及查詢接口方法list()/iterator()方法時(shí)候,如果session中不存在該對象,那么會先將本次的對象存儲到一級緩存中便于以后使用,當(dāng)Session關(guān)閉時(shí)同時(shí)清空一級緩存數(shù)據(jù)。clear()/evict() Session的緩存作用 減少訪問數(shù)據(jù)庫的次數(shù),進(jìn)而提高效率。保證緩存中的對象與數(shù)據(jù)庫的記錄保持 同步,當(dāng)緩存的對象改變后,session不會立即執(zhí)行sql,而是將多個(gè)sql語句合并 為一條sql進(jìn)行執(zhí)行,提高效率。 session的緩存舉例 當(dāng)用戶需要對指定的對象進(jìn)行修改的時(shí)候,如果對于同一個(gè)屬性修改了多次,其實(shí)hibernate的session緩存并不是執(zhí)行多個(gè)update語句,而是以最后一個(gè)更新為準(zhǔn)而發(fā)送一條更新的sql。b)hibernate中的session緩存問題Get()先將獲取的對象存儲到一級緩存,當(dāng)再次加載同一個(gè)持久化對象的時(shí)候先檢測一級緩存中是否有該對象,如果有直接獲取,不會發(fā)送SQL語句,否則才發(fā)送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()查詢出來的結(jié)果會被緩存起來,那么當(dāng)
terator()再查看的時(shí)候會先發(fā)送查詢id的SQL,
但是查詢實(shí)體的SQL不會發(fā)出,因?yàn)樗紫然厝ヒ?/strong>
級緩存中獲取已經(jīng)緩存的數(shù)據(jù)。
D)緩存相關(guān)幾個(gè)方法的作用
session.flush(); 讓一級緩存與數(shù)據(jù)庫同步
session.evict(arg0); 清空一級緩存中指定的對象
session.clear(); 清空一級緩存中緩存的所有對象
在什么情況用上面方法?
批量操作使用使用:
Session.flush(); // 先與數(shù)據(jù)庫同步
Session.clear(); // 再清空一級緩存內(nèi)容
1)Hibenate中一級緩存,也叫做session的緩存,它可以在session范圍內(nèi)減少數(shù)據(jù)庫的訪問次數(shù)! 只在session范圍有效!Session關(guān)閉,一級緩存失效!
2)當(dāng)調(diào)用session的save/saveOrUpdate/get/load/list/iterator方法的時(shí)候,都會把對象放入session的緩存中。
3)Session的緩存由hibernate維護(hù), 用戶不能操作緩存內(nèi)容; 如果想操作緩存內(nèi)容,必須通過hibernate提供的evit/clear方法操作。
特點(diǎn):
只在(當(dāng)前)session范圍有效,作用時(shí)間短,效果不是特別明顯!
在短時(shí)間內(nèi)多次操作數(shù)據(jù)庫,效果比較明顯!
面試題1: 不同的session是否會共享緩存數(shù)據(jù)?
不會。
Session session1=sessionFactory.openSession();Session session2=sessionFactory.openSession();Transaction tx1 = session1.beginTransaction(); Transaction tx2 = session2.beginTransaction();//Customer對象被session1關(guān)聯(lián)Customer c=(Customer)session1.get(Customer.class,new Long(1)); //Customer對象被session2關(guān)聯(lián)session2.update(c); c.setName("Jack"); //修改Customer對象的屬性tx1.commit(); //執(zhí)行update語句 tx2.commit(); //執(zhí)行update語句session1.close(); session2.close();當(dāng)執(zhí)行session1的load()方法時(shí),OID為1的Customer對象被加入到session1的緩存中,因此它是session1的持久化對象,此時(shí)它還沒有被session2關(guān)聯(lián),因此相對于session2,它處于游離狀態(tài)。當(dāng)執(zhí)行session2的update()方法時(shí),Customer對象被加入到session2的緩存中,因此也成為session2的持久化對象。接下來修改Customer對象的name屬性,會導(dǎo)致兩個(gè)Session實(shí)例在清理各自的緩存時(shí),都執(zhí)行相同的update語句:update CUSTOMERS set NAME='Jack' …… where ID=1;? 面試題2: list與iterator查詢的區(qū)別?list() 一次把所有的記錄都查詢出來,會放入緩存,但不會從緩存中獲取數(shù)據(jù) Iterator N+1查詢; N表示所有的記錄總數(shù) 即會先發(fā)送一條語句查詢所有記錄的主鍵(1),再根據(jù)每一個(gè)主鍵再去數(shù)據(jù)庫查詢(N)!會放入緩存,也會從緩存中取數(shù)據(jù)!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) // 測試時(shí)候使用 .buildSessionFactory(); } @Test public void testCache() throws Exception { Session session = sf.openSession(); session.beginTransaction(); User user = null; // 查詢 user = (User) session.get(User.class, 5); // 先檢查緩存中是否有數(shù)據(jù),如果有不查詢數(shù)據(jù)庫,直接從緩存中獲取 user = (User) session.get(User.class, 5); // 先檢查緩存中是否有數(shù)據(jù),如果有不查詢數(shù)據(jù)庫,直接從緩存中獲取 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"); // 緩存數(shù)據(jù)與數(shù)據(jù)庫同步 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); // 清空緩存內(nèi)容 // 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的緩存區(qū) User user = (User) session1.get(User.class, 1); // user放入session2的緩存區(qū) 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) // 測試時(shí)候使用 .buildSessionFactory(); } /** * list與iterator區(qū)別 * 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()) { // 得到當(dāng)前迭代的每一個(gè)對象 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(); /**************執(zhí)行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)); } /**************執(zhí)行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 【會放入緩存,但不會從緩存中獲取數(shù)據(jù)】 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方法區(qū)別?get: 及時(shí)加載,只要調(diào)用get方法立刻向數(shù)據(jù)庫查詢load:默認(rèn)使用懶加載,當(dāng)用到數(shù)據(jù)的時(shí)候才向數(shù)據(jù)庫查詢。 懶加載:(lazy)概念:當(dāng)用到數(shù)據(jù)的時(shí)候才向數(shù)據(jù)庫查詢,這就是hibernate的懶加載特性。目的:提供程序執(zhí)行效率! lazy 值true 使用懶加載false 關(guān)閉懶加載extra (在集合數(shù)據(jù)懶加載時(shí)候提升效率)在真正使用數(shù)據(jù)的時(shí)候才向數(shù)據(jù)庫發(fā)送查詢的sql;如果調(diào)用集合的size()/isEmpty()方法,只是統(tǒng)計(jì),不真正查詢數(shù)據(jù)! 懶加載異常 Session關(guān)閉后,不能使用懶加載數(shù)據(jù)! 如果session關(guān)閉后,使用懶加載數(shù)據(jù)報(bào)錯(cuò):org.hibernate.LazyInitializationException: could not initialize proxy - no Session如何解決session關(guān)閉后不能使用懶加載數(shù)據(jù)的問題? // 方式1: 先使用一下數(shù)據(jù)//dept.getDeptName();// 方式2:強(qiáng)迫代理對象初始化Hibernate.initialize(dept);// 方式3:關(guān)閉懶加載設(shè)置lazy=false;// 方式4: 在使用數(shù)據(jù)之后,再關(guān)閉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; // 【一對多】 部門對應(yīng)的多個(gè)員工 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> <!-- 集合屬性,默認(rèn)使用懶加載 lazy true 懶加載 extra 懶加載(智能) false 關(guān)閉懶加載 --> <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) // 測試時(shí)候使用 .buildSessionFactory(); } //1. 主鍵查詢,及區(qū)別 @Test public void get_load() { Session session = sf.openSession(); session.beginTransaction(); Dept dept = new Dept(); // get: 及時(shí)查詢// dept = (Dept) session.get(Dept.class, 9);// System.out.println(dept.getDeptName()); // load,默認(rèn)懶加載, 及在使用數(shù)據(jù)的時(shí)候,才向數(shù)據(jù)庫發(fā)送查詢的sql語句! dept = (Dept)session.load(Dept.class, 9); // 方式1: 先使用一下數(shù)據(jù) //dept.getDeptName(); // 方式2:強(qiáng)迫代理對象初始化 Hibernate.initialize(dept); // 方式3:關(guān)閉懶加載 session.getTransaction().commit(); session.close(); // 在這里使用 System.out.println(dept.getDeptName()); } //1. 主鍵查詢,及區(qū)別 @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.一對一映射需求: 用戶與身份證信息 一條用戶記錄對應(yīng)一條身份證信息! 一對一的關(guān)系!設(shè)計(jì)數(shù)據(jù)庫:JavaBean:映射:package com.xp.c_one2one;public class IdCard { // 身份證號(主鍵) private String cardNum;// 對象唯一表示(Object Identified, OID) private String place; // 身份證地址 // 身份證與用戶,一對一的關(guān)系 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; // 用戶與身份證信息, 一對一關(guān)系 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) // 測試時(shí)候使用 .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"); // 關(guān)系 idCard.setUser(user); // ----保存---- session.save(idCard); session.getTransaction().commit(); session.close(); }}基于主鍵的映射// 身份證public class IdCard { private int user_id; // 身份證號 private String cardNum; private String place; // 身份證地址 // 身份證與用戶,一對一的關(guān)系 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 節(jié)點(diǎn)指定的是主鍵映射, 即user_id是主鍵 主鍵生成方式: foreign 即把別的表的主鍵作為當(dāng)前表的主鍵; property (關(guān)鍵字不能修改)指定引用的對象 對象的全名 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.組件映射類組合關(guān)系的映射,也叫做組件映射!注意:組件類和被包含的組件類,共同映射到一張表!需求: 汽車與車輪數(shù)據(jù)庫 T_car 主鍵 汽車名稱 輪子大小 個(gè)數(shù)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.繼承映射需求:動(dòng)物貓猴子動(dòng)物類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); // 獲取時(shí)候注意:當(dāng)寫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(); }} 簡單繼承映射,有多少個(gè)子類,寫多少個(gè)映射文件!8.繼承映射2需求:貓、猴子、動(dòng)物。所有子類映射到一張表 (1張表)什么情況用? 子類教多,且子類較為簡單,即只有個(gè)別屬性! 好處:因?yàn)槭褂靡粋€(gè)映射文件, 減少了映射文件的個(gè)數(shù)。 缺點(diǎn):(不符合數(shù)據(jù)庫設(shè)計(jì)原則)一個(gè)映射文件: Animal.hbm.xml (如何區(qū)分是哪個(gè)子類的信息?)數(shù)據(jù)庫: T_animal (要存儲所有的子類信息) “鑒別器” Id name catchMouse eatBanana type_(區(qū)別是哪個(gè)子類) 1 大馬猴 NULL 吃10個(gè)香蕉 猴子 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"/> <!-- 子類:貓 每個(gè)子類都用subclass節(jié)點(diǎn)映射 注意:一定要指定鑒別器字段,否則報(bào)錯(cuò)! 鑒別器字段:作用是在數(shù)據(jù)庫中區(qū)別每一個(gè)子類的信息, 就是一個(gè)列 discriminator-value="cat_" 指定鑒別器字段,即type_字段的值 如果不指定,默認(rèn)為當(dāng)前子類的全名 --> <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個(gè)香蕉"); // 保存 session.save(cat); session.save(m); session.getTransaction().commit(); session.close(); }}總結(jié): 寫法較為簡單:所有子類用一個(gè)映射文件,且映射到一張表! 但數(shù)據(jù)庫設(shè)計(jì)不合理! (不推薦用。)每個(gè)類映射一張表(3張表)數(shù)據(jù)庫 T_anmal (存儲父類信息) 1 大花貓 T_cat (引用父類的主鍵) 1 抓小老鼠T_monkey(引用父類的主鍵)Javabean設(shè)計(jì)一樣,映射實(shí)現(xiàn)不同:<!-- 繼承映射, 每個(gè)類對應(yīng)一張表(父類也對應(yīng)表) --><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>總結(jié): 一個(gè)映射文件,存儲所有的子類; 子類父類都對應(yīng)表; 缺點(diǎn):表結(jié)構(gòu)比較負(fù)責(zé),插入一條子類信息,需要用2條sql: 往父類插入、往子類插入!(推薦)每個(gè)子類映射一張表, 父類不對應(yīng)表(2張表)數(shù)據(jù)庫: T_cat Id name catchMounse T_monkey Id name eatBanana<union-subclass name="Cat" table="t_cat"> <property name="catchMouse"></property> </union-subclass>注意:主鍵不能是自增長!總結(jié): 所有的子類都寫到一個(gè)映射文件;父類不對應(yīng)表; 每個(gè)子類對應(yīng)一張表<?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"><!-- 繼承映射, 每個(gè)類對應(yīng)一張表(父類也對應(yīng)表) --><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"><!-- 繼承映射, 每個(gè)類對應(yīng)一張表(父類不對應(yīng)表) --><hibernate-mapping package="cn.itcast.e_extends4"> <!-- abstract="true" 指定實(shí)體類對象不對應(yīng)表,即在數(shù)據(jù)庫段不生成表 --> <class name="Animal" abstract="true"> <!-- 如果用union-subclass節(jié)點(diǎn),主鍵生成策略不能為自增長! --> <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中映射: 多對一 一對多 多對多 一對一 (多對一的特殊應(yīng)用) 組件 繼承
新聞熱點(diǎn)
疑難解答