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