對象的狀態(tài)
- Hibernate中對象的狀態(tài) : 臨時/瞬時狀態(tài)雇初、持久化狀態(tài)、游離狀態(tài)
- 臨時狀態(tài)
- 特點:
- 直接new出來的對象;
- 不處于session的管理;
- 數(shù)據(jù)庫中沒有對象的記錄;
- 特點:
- 持久化狀態(tài) : 當調(diào)用session的save/saveOrUpdate/get/load/list等方法的時候屋谭,對象就是持久化狀態(tài)。處于持久化狀態(tài)的對象帖汞,當對對象屬性進行更改的時候戴而,會反映到數(shù)據(jù)庫中!
- 特點:
- 處于session的管理;
- 數(shù)據(jù)庫中有對應的記錄;
- 特點:
- 游離狀態(tài)
- 特點
- 不處于session的管理
- 數(shù)據(jù)庫中有對應的記錄
- Session關(guān)閉后,對象的狀態(tài)
- 特點
- 臨時狀態(tài)
- 對象狀態(tài)的轉(zhuǎn)換 :
private static SessionFactory sf;
static {
sf = new Configuration()
.configure()
.addClass(User.class) // 測試時候使用
.buildSessionFactory();
}
//1. 對象狀態(tài)的轉(zhuǎn)換
@Test
public void testSaveSet() throws Exception {
Session session = sf.openSession();
session.beginTransaction();
// 創(chuàng)建對象 【臨時狀態(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會自動與數(shù)據(jù)庫匹配(一級緩存)翩蘸,如果一樣就更新數(shù)據(jù)庫
session.getTransaction().commit();
session.close();
user.setUserName("Jack444444444");
// 打印 【游離狀態(tài)】
System.out.println(user.getUserId());
System.out.println(user.getUserName());
}
一級緩存
-
為什么要用緩存所意?
- 目的:減少對數(shù)據(jù)庫的訪問次數(shù)!從而提升hibernate的執(zhí)行效率催首!
-
Hibernate中緩存分類 :
- 一級緩存
- 二級緩存
一級緩存概念 :
1)Hibenate中一級緩存扶踊,也叫做session的緩存,它可以在session范圍內(nèi)減少數(shù)據(jù)庫的訪問次數(shù)! 只在session范圍有效郎任! Session關(guān)閉秧耗,一級緩存失效!
2)當調(diào)用session的save/saveOrUpdate/get/load/list/iterator方法的時候,都會把對象放入session的緩存中舶治。
3)Session的緩存由hibernate維護分井, 用戶不能操作緩存內(nèi)容车猬; 如果想操作緩存內(nèi)容,必須通過hibernate提供的evit/clear方法操作尺锚。-
特點:
- 只在(當前)session范圍有效珠闰,作用時間短,效果不是特別明顯瘫辩!
- 在短時間內(nèi)多次操作數(shù)據(jù)庫伏嗜,效果比較明顯!
-
緩存相關(guān)幾個方法的作用
-
session.flush()
: 讓一級緩存與數(shù)據(jù)庫同步 -
session.evict(arg0)
: 清空一級緩存中指定的對象 -
session.clear()
: 清空一級緩存中緩存的所有對象
-
-
在什么情況用上面方法伐厌?
- 批量操作使用使用:
- Session.flush(); // 先與數(shù)據(jù)庫同步
- Session.clear(); // 再清空一級緩存內(nèi)容
- 批量操作使用使用:
-
查詢方法:
- list : 會放入緩存承绸,但不會從緩存中獲取數(shù)據(jù)
private static SessionFactory sf;
static {
sf = new Configuration()
.configure()
.addClass(User.class) // 測試時候使用
.buildSessionFactory();
}
@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();
}
- iterator : 會放入緩存,也會從緩存中獲取數(shù)據(jù)
private static SessionFactory sf;
static {
sf = new Configuration()
.configure()
.addClass(User.class) // 測試時候使用
.buildSessionFactory();
}
@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();
}
懶加載(lazy)
- 概念:當用到數(shù)據(jù)的時候才向數(shù)據(jù)庫查詢挣轨,這就是hibernate的懶加載特性军熏。
- 目的:提供程序執(zhí)行效率!
- lazy 值
- true : 使用懶加載
- false : 關(guān)閉懶加載
- extra : 在集合數(shù)據(jù)懶加載時候提升效率
- 在真正使用數(shù)據(jù)的時候才向數(shù)據(jù)庫發(fā)送查詢的sql卷扮;如果調(diào)用集合的size() / isEmpty()方法羞迷,只是統(tǒng)計,不真正查詢數(shù)據(jù)画饥!
<?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.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 關(guān)閉懶加載
-->
<set name="emps" lazy="extra">
<key column="dept_id"></key>
<one-to-many class="Employee"/>
</set>
</class>
</hibernate-mapping>
//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();
}
- 懶加載異常
- Session關(guān)閉后蚊惯,不能使用懶加載數(shù)據(jù); 如果session關(guān)閉后切威,使用懶加載數(shù)據(jù)報錯:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
- 如何解決session關(guān)閉后不能使用懶加載數(shù)據(jù)的問題痛阻?
- 方式1: 先使用一下數(shù)據(jù) :
dept.getDeptName();
- 方式2:強迫代理對象初始化 :
Hibernate.initialize(dept);
- 方式3:關(guān)閉懶加載, 設(shè)置lazy=false;
- 方式4: 在使用數(shù)據(jù)之后速兔,再關(guān)閉session进倍!
- 方式1: 先使用一下數(shù)據(jù) :
- Session關(guān)閉后蚊惯,不能使用懶加載數(shù)據(jù); 如果session關(guān)閉后切威,使用懶加載數(shù)據(jù)報錯:
- get與load方法:
private static SessionFactory sf;
static {
sf = new Configuration()
.configure()
.addClass(Dept.class)
.addClass(Employee.class) // 測試時候使用
.buildSessionFactory();
}
//1. 主鍵查詢纽窟,及區(qū)別
@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填具,默認懶加載偷办, 及在使用數(shù)據(jù)的時候艰额,才向數(shù)據(jù)庫發(fā)送查詢的sql語句!
dept = (Dept)session.load(Dept.class, 9);
// 方式1: 先使用一下數(shù)據(jù)
//dept.getDeptName();
// 方式2:強迫代理對象初始化
Hibernate.initialize(dept);
// 方式3:關(guān)閉懶加載
session.getTransaction().commit();
session.close();
// 在這里使用
System.out.println(dept.getDeptName());
}
一對一映射
- 基于外鍵的映射
- IdCard.hbm.xml :
<?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>
- User.hbm.xml :
<?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>
- java類
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");
// 關(guān)系
idCard.setUser(user);
// ----保存----
session.save(idCard);
session.getTransaction().commit();
session.close();
}
- 基于主鍵的映射
- IdCard.hbm.xml :
<?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é)點指定的是主鍵映射, 即user_id是主鍵
主鍵生成方式: foreign 即把別的表的主鍵作為當前表的主鍵柄沮;
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>
- User.hbm.xml :
<?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>
- java類
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");
// 關(guān)系
idCard.setUser(user);
// ----保存----
session.save(idCard);
session.getTransaction().commit();
session.close();
}
組件映射與繼承映射
-
類的關(guān)系
- 組合關(guān)系 : 一個類中包含了另外一個類, 這兩個類就是組合關(guān)系 (汽車與車輪)
- 繼承關(guān)系 : 一個類繼承另外一個類, 這兩個類就是繼承關(guān)系
-
組件映射 : 類組合關(guān)系的映射, 也叫做組件映射 (組件類和被包含的組件類,共同映射到一張表)
- javaBean
public class Car {
private int id;
private String name;
// 車輪
private Wheel wheel;
}
public class Wheel {
private int count;
private int size;
}
- Car.hbm.xml
<?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.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>
- java
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();
}
- 繼承映射
- 簡單繼承映射 : 有多少個子類湖苞,寫多少個映射文件拯欧!
<?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_extends1">
<class name="Cat" table="t_Cat">
<!-- 簡單繼承映射: 父類屬性直接寫 -->
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
<property name="catchMouse"></property>
</class>
</hibernate-mapping>
- 總結(jié):寫法較為簡單, 所有子類用一個映射文件, 且映射到一張表; 但數(shù)據(jù)庫設(shè)計不合理!(不推薦用)
- 一個映射文件存儲所有子類, 子類父類都對應表(所有子類映射到一張表)
<?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>
<!-- 指定鑒別器字段(區(qū)分不同的子類) -->
<discriminator column="type_"></discriminator>
<property name="name"></property>
<!--
子類:貓
每個子類都用subclass節(jié)點映射
注意:一定要指定鑒別器字段财骨,否則報錯镐作!
鑒別器字段:作用是在數(shù)據(jù)庫中區(qū)別每一個子類的信息藏姐, 就是一個列
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>
- 總結(jié) : 寫法較為簡單, 所有子類用一個映射文件, 且映射到一張表该贾!但數(shù)據(jù)庫設(shè)計不合理(不推薦用)
- 每個類都映射一張表
<?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_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é) : 一個映射文件,存儲所有的子類靶庙; 子類父類都對應表问畅;
- 缺點:表結(jié)構(gòu)比較復雜,插入一條子類信息六荒,需要用2條sql(子類, 父類都需要插入數(shù)據(jù))
- 推薦 : 每個子類映射一張表护姆, 父類不對應表
<?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" 指定實體類對象不對應表掏击,即在數(shù)據(jù)庫段不生成表 -->
<class name="Animal" abstract="true">
<!-- 如果用union-subclass節(jié)點卵皂,主鍵生成策略不能為自增長! -->
<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中映射分類:
- 多對一
- 一對多
- 多對多
- 一對一 (多對一的特殊應用)
- 組件
- 繼承