1. 程式人生 > >hibernate筆記(三)

hibernate筆記(三)

assigned abstract isempty native lin 清空 pen 一對多 pan

目標:

1部分: 對象的狀態:

2部分:緩存

1) 一級緩存

2) 相關知識

----懶加載---

3部分:映射

一對一映射

組件映射

繼承映射

一、對象的狀態

舉例: User user = new User();

Hibernate中對象的狀態: 臨時/瞬時狀態、持久化狀態、遊離狀態。

臨時狀態

特點:

直接new出來的對象;

不處於session的管理;

數據庫中沒有對象的記錄;

持久化狀態

當調用sessionsave/saveOrUpdate/get/load/list等方法的時候,對象就是持久化狀態。

處於持久化狀態的對象,當對對象屬性進行更改的時候,會反映到數據庫中!

特點:

處於session的管理;

數據庫中有對應的記錄;

遊離狀態

特點

不處於session的管理;

數據庫中有對應的記錄

Session關閉後,對象的狀態;

對象狀態的轉換,

二、一級緩存

為什麽要用緩存?

目的:減少對數據庫的訪問次數!從而提升hibernate的執行效率!

Hibernate中緩存分類:

一級緩存

二級緩存

概念

1Hibenate中一級緩存,也叫做session的緩存,它可以在session範圍內減少數據庫的訪問次數! 只在session範圍有效! Session關閉,一級緩存失效!

2)當調用sessionsave/saveOrUpdate/get/load/list/iterator

方法的時候,都會把對象放入session的緩存中。

3Session的緩存由hibernate維護, 用戶不能操作緩存內容; 如果想操作緩存內容,必須通過hibernate提供的evit/clear方法操作。

特點:

只在(當前)session範圍有效,作用時間短,效果不是特別明顯!

在短時間內多次操作數據庫,效果比較明顯!

緩存相關幾個方法的作用

session.flush(); 讓一級緩存與數據庫同步

session.evict(arg0); 清空一級緩存中指定的對象

session.clear(); 清空一級緩存中緩存的所有對象

在什麽情況用上面方法?

批量操作使用使用:

Session.flush(); // 先與數據庫同步

Session.clear(); // 再清空一級緩存內容

面試題1: 不同的session是否會共享緩存數據?

不會。

User1 u1 = Session1.get(User.class,1); u1對象放入session1的緩存

Session2.update(u1); u1放入session2的緩存

U1.setName(‘new Name’);

如果生成2update sql, 說明不同的session使用不同的緩存區,不能共享。

面試題2listiterator查詢的區別?

list()

一次把所有的記錄都查詢出來,

會放入緩存,但不會從緩存中獲取數據

Iterator

N+1查詢; N表示所有的記錄總數

即會先發送一條語句查詢所有記錄的主鍵(1),

再根據每一個主鍵再去數據庫查詢(N)!

會放入緩存,也會從緩存中取數據!

三、懶加載

面試題3getload方法區別?

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

四、一對一映射

需求: 用戶與身份證信息

一條用戶記錄對應一條身份證信息! 一對一的關系!

設計數據庫:

JavaBean

映射:

基於外鍵的映射

// 身份證

public class IdCard {

// 身份證號(主鍵)

private String cardNum;// 對象唯一表示(Object Identified, OID)

private String place; // 身份證地址

// 身份證與用戶,一對一的關系

private User user;

// 用戶

public class User {

private int userId;

private String userName;

// 用戶與身份證信息, 一對一關系

private IdCard idCard;

<?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_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>

<?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_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>

基於主鍵的映射

// 身份證

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.xmltable(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>

五、組件映射與繼承映射

類的關系

組合關系

一個類中包含了另外一個類。這2個類中就是組合關系。

需求: 汽車與車輪

繼承關系

一個類繼承另外一個類。這2個類中就是繼承關系。

需求:動物

猴子

組件映射

類組合關系的映射,也叫做組件映射!

註意:組件類和被包含的組件類,共同映射到一張表!

需求: 汽車與車輪

數據庫

T_car

主鍵 汽車名稱 輪子大小 個數

Javabean

public class Car {

private int id;

private String name;

// 車輪

private Wheel wheel;

}

// 車輪

public class Wheel {

private int count;

private int size;

}

<hibernate-mapping package="cn.itcast.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>

繼承映射

需求:動物

猴子

簡單繼承映射

// 動物類

public abstract class Animal {

private int id;

private String name;

<!--

簡單繼承

-->

<hibernate-mapping package="cn.itcast.e_extends1">

<class name="Cat" table="t_Cat">

<!-- 簡單繼承映射: 父類屬性直接寫 -->

<id name="id">

<generator class="native"></generator>

</id>

<property name="na"></property>

<property name="catchMouse"></property>

</class>

</hibernate-mapping>

@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();

}

總結:

簡單繼承映射,有多少個子類,寫多少個映射文件!

繼承映射

需求:貓、猴子、動物。

所有子類映射到一張表 (1張表)

什麽情況用?

子類教多,且子類較為簡單,即只有個別屬性!

好處:因為使用一個映射文件, 減少了映射文件的個數。

缺點:(不符合數據庫設計原則)

一個映射文件: Animal.hbm.xml

(如何區分是哪個子類的信息?)

數據庫:

T_animal (要存儲所有的子類信息) “鑒別器”

Id name catchMouse eatBanana type_(區別是哪個子類)

1 大馬猴 NULL 10個香蕉 猴子

2 大花貓 不抓老鼠 NULL

總結:

寫法較為簡單:所有子類用一個映射文件,且映射到一張表!

但數據庫設計不合理!

(不推薦用。)

每個類映射一張表(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>

總結:

一個映射文件,存儲所有的子類; 子類父類都對應表;

缺點:表結構比較復雜,插入一條子類信息,需要用2sql: 往父類插入、往子類插入!

(推薦)每個子類映射一張表, 父類不對應表(2張表)

數據庫:

T_cat

Id name catchMounse

T_monkey

Id name eatBanana

<union-subclass name="Cat" table="t_cat">

<property name="catchMouse"></property>

</union-subclass>

註意:主鍵不能是自增長!

總結:

所有的子類都寫到一個映射文件;

父類不對應表; 每個子類對應一張表

Hibernate中映射:

多對一

一對多

多對多

一對一 (多對一的特殊應用)

組件

繼承

hibernate筆記(三)