JavaEE的三層結(jié)構(gòu)
- web層:struts2框架
- service層:spring框架
- dao層:hibernate框架
MVC思想 - m:模型
- v:視圖
- c:控制器
1 Hibernate概述
1.1 框架
1.1.1 通俗理解
就是少寫部分代碼實(shí)現(xiàn)功能
1.2 Hibernate框架
- hibernate框架應(yīng)用在JavaEE三層結(jié)構(gòu)中的dao層
- 在dao層hibernate實(shí)現(xiàn)CRUD操作,hibernate底層就是JDBC,對JDBC進(jìn)行封裝,好處是不需要寫復(fù)雜的
JDBC代碼了,不需要寫SQL語句實(shí)現(xiàn) - hibernate開源輕量級框架
- hibernate 版本
Hibernate3.x
Hibernate4.x
Hibernate5.x(2017最新)
1.3 底層實(shí)現(xiàn)
1.3.1 ORM思想
- hibernate使用ORM思想對數(shù)據(jù)庫進(jìn)行CRUD操作
- 在web階段學(xué)習(xí)Javabean更正確的叫法交:實(shí)體類
- ORM:Object Relational Mapping 對象關(guān)系映射
讓 實(shí)體類和 數(shù)據(jù)庫 表進(jìn)行一一對應(yīng)關(guān)系
讓 實(shí)體類和 數(shù)據(jù)庫 表進(jìn)行對應(yīng)
讓 實(shí)體類 屬性 和 表 里面 字段 對應(yīng)
不需要操作數(shù)據(jù)庫而是直接操作對應(yīng)的實(shí)體類對象
2 Hibernate使用
2.1 入門
2.1.1 hibernate開發(fā)環(huán)境搭建
1)導(dǎo)入jar包
下載hibernate-release-5.2.10.Final
①壓縮包中的lib中的required文件夾內(nèi)的jar包
②jpa的jar包也在required內(nèi)
③日志jar包.hibernate本身沒有日志輸出jar包,需導(dǎo)入其他日志輸出jar包 log4j,slf4j-log4j,slf4j-api
④mysqk驅(qū)動(dòng)jar包mysql-connector-java
2)創(chuàng)建實(shí)體Bean類
hibernate 要求有個(gè)實(shí)體類有一個(gè)屬性唯一
(可以手動(dòng)在mysql中創(chuàng)建表與bean類屬性對應(yīng),也可以由hibernate自己創(chuàng)建)
package cn.wanxp.entity;
public class User {
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
/*hibernate 要求有個(gè)實(shí)體類有一個(gè)屬性唯一*/
private int uid;
private String username;
private String password;
private String address;
}
3) 配置實(shí)體類和數(shù)據(jù)庫表一一對應(yīng)關(guān)系(映射關(guān)系)
實(shí)用配置文件實(shí)現(xiàn)映射關(guān)系
(1) 創(chuàng)建xml格式的配置文件
映射文件的名稱和位置沒有固定要求
-- 建議在實(shí)體類的所在包內(nèi) 實(shí)體類名稱.hbm.xml
(2) 配置文件是xml格式,在配置文件中引入xml約束
-- hibernate里面引入的約束是dtd格式
(3)在包內(nèi)創(chuàng)建映射文件User.hbm.xml
約束可以是本地文件在hibernate-release-5.2.10.Final內(nèi)可搜索到,復(fù)制與User放一起然后寫
<!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
也可以是網(wǎng)上公用的DTD文件,如果是使用網(wǎng)上的dtd約束則
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 上面這段約束可在hibernate-mapping-3.0.dtd中開頭部分找到 -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<!-- 1配置類和表對應(yīng)
class標(biāo)簽
name 屬性: 實(shí)體類全路徑
table 屬性:數(shù)據(jù)庫名稱(隨意名稱)
-->
<class name="cn.wanxp.entity.User" table="t_user">
<!-- 2配置實(shí)體類id和表id一一對應(yīng)
要求兩id在各自位置具有唯一性
-->
<!--
id標(biāo)簽
name屬性: 實(shí)體類里面id屬性名稱
column屬性:生成表字段名稱(名稱隨意)
-->
<id name="uid" column="uid">
<!--設(shè)置數(shù)據(jù)表id增長策略
native 生成表id是主鍵和自增長
-->
<generator class="native"></generator>
</id>
<!-- 配置其他屬性與字段對應(yīng)
name屬性:實(shí)體類屬性名稱
column屬性:數(shù)據(jù)表字段名稱
-->
<property name="username" column="username"></property>
<property name="password" column="password"></property>
<property name="address" column="address"></property>
</class>
</hibernate-mapping>
4)創(chuàng)建hibernate的核心配置文件
(1)核心配置文件格式xml,配置文件名稱和位置固定
-位置: 必須src下面
-名稱: 必須hibernate.cfg.xml
(2)引入約束
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
(3)hibernate 操作過程中只會(huì)加載核心配置文件,其它配置文件不會(huì)加載
第一部分:配置數(shù)據(jù)庫信息
第二部分:配置hibernate信息
第三部分:映射文件放在核心配置文件中
注意
①方言
注意下面的這句:是MySQL5Dialect,不是properties文件中的MySQLDialect因?yàn)榘姹静灰粯恿耍?br>
不然無法創(chuàng)建表。原因就是使用沒有5的會(huì)用創(chuàng)建命令type=,而不是engine=
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
②字符集
-1- 如要使用字符集utf8,想要支持中文時(shí):
先創(chuàng)建數(shù)據(jù)庫database加上字符集:create database hibernate_day01 charset utf8 ;
然后在hibernate.cfg.xml加上下面標(biāo)簽屬性,表示和數(shù)據(jù)庫傳遞數(shù)據(jù)采用utf8編碼
<property name="connection.useUnicode">true</property>
<property name="connection.characterEncoding">UTF-8</property>
hibernate.cfg.xml文件如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 第一部分:配置數(shù)據(jù)庫信息
在下載的hibernate-release壓縮包文件夾內(nèi)搜索hibernate.properties打開后可看到對應(yīng)的數(shù)據(jù)庫需要配置的屬性
-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_day01</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="connection.useUnicode">true</property>
<property name="connection.characterEncoding">UTF-8</property>
<!-- 第二部分:配置hibernate信息,可選的,可以配置也可以不用配置
同樣能在hibernate.properties搜索到相應(yīng)的值
-->
<!-- 如:輸出底層sql語句 -->
<property name="hibernate.show_sql">true</property>
<!-- 如:格式化底層sql語句 -->
<property name="hibernate.format_sql">true</property>
<!-- 如:hibernate創(chuàng)建表,需要配置后
update:如果已經(jīng)存在表則更新,若不存在則創(chuàng)建
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置數(shù)據(jù)庫方言
mysql里實(shí)現(xiàn)分頁關(guān)鍵字 limit 只能在mysql里面
Oracle數(shù)據(jù)庫,實(shí)現(xiàn)分頁rownum
在hibernate框架識(shí)別不同數(shù)據(jù)庫自己特有的語句
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 第三部分:配置映射文件 -->
<!-- resource引入路徑根目錄是src -->
<mapping resource="/cn/wanxp/entity/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
5)測試 添加操作 1-4,6,7寫法基本都是固定的,變化的只有第5步
(1)加載hibernate核心配置文件
(2)創(chuàng)建SessionFactory對象
(3)使用SessionFactory創(chuàng)建session對象
(4)開啟事務(wù)
(5)寫具體邏輯
(6)提交事務(wù)
(7)關(guān)閉資源
示例如下
package cn.wanxp.hibernatetest;
import java.io.UnsupportedEncodingException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import cn.wanxp.entity.User;
public class HibernateDemo {
@Test
public void testAdd() {
// (1)加載hibernate核心配置文件
//在hibernate里面封裝對象
//將會(huì)到src下找到hibernate.cfg.xml的文件
Configuration cfg = new Configuration();
cfg.configure();
// (2)創(chuàng)建SessionFactory對象
//讀取hibernate核心配置文件,創(chuàng)建SessionFactory
//過程中根據(jù)配置文件中的屬性以及映射關(guān)系xml文件創(chuàng)建表
SessionFactory sessionFactory=cfg.buildSessionFactory();
// (3)使用SessionFactory創(chuàng)建session對象
//類似于JDBC連接
Session session = sessionFactory.openSession();
// (4)開啟事務(wù)
Transaction tx = session.beginTransaction();
// (5)寫具體邏輯編寫CRUD操作
User user = new User();
String username="張三";
user.setUsername(username);
user.setPassword("password1");
user.setAddress("上海");
session.save(user);
// (6)提交事務(wù)
tx.commit();
// (7)關(guān)閉資源
session.close();
sessionFactory.close();
}
}
效果如下:

2 hibernate詳解
2.1 hibernate配置文件
2.1.1 hibernate映射配置文件
- 映射文件沒有固定位置
映射配置文件中,標(biāo)簽name屬性寫實(shí)體類中的屬性名;column可以不用寫,字段名就會(huì)命名為實(shí)體類屬性同一名字。
property標(biāo)簽type屬性可以設(shè)置數(shù)據(jù)表的字段屬性。
2.1.2 核心配置文件
標(biāo)簽位置要求:
<hibernate-configuration>
<session-factory>
...
</session-factory>
</hibernate-configuration>
配置的三部分要求
- 數(shù)據(jù)庫部分--必須
- hibernate部分--可選
- 映射文件--必須
2.2 hibernate核心api
2.2.1 Configuration
Configuration cfg = new Configuration();
cfg.configure();
上面代碼的過程:從src下找到hibernate.cfg.xml文件并根據(jù)里面的配置,創(chuàng)建對象并加載
2.2.2 SessionFactory
- 根據(jù)配置文件中的屬性創(chuàng)建表
<!-- 如:hibernate創(chuàng)建表,需要配置后
update:如果已經(jīng)存在表則更新,若不存在則創(chuàng)建
-->
<property name="hibernate.hbm2ddl.auto">update</property>
- 創(chuàng)建SessionFactory過程,特別耗費(fèi)資源,所以一般一個(gè)項(xiàng)目只創(chuàng)建一次
- 具體實(shí)現(xiàn)
(1)寫工具類,寫靜態(tài)代碼塊
package cn.wanxp.utils;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static Configuration cfg = null;
private static SessionFactory sessionFactory = null;
static {
cfg = new Configuration();
cfg.configure();
sessionFactory = cfg.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
2.2.3 Session
- Sesssion不同方法實(shí)現(xiàn)CRUD操作
(1) 添加:save
(2) 修改:update
(3) 刪除:delete
(4) 根據(jù)id查詢:get - session對象單線程對象
(1) session對象不能共用,只能自己使用
2.2.4 Transaction
- 事務(wù)對象
Transaction tx = session.beginTransaction();
- 事物提交和回滾方法
tx.commit();
tx.rollback();
- 事物
(1) 事物四個(gè)特性
原子性、一致性、隔離性、持久性
2.3 配置文件沒有提示
復(fù)制下面的uri
http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd
Eclipse->Preferences->XML Catalog->Add->
location---找到hibernate-configuration-3.0.dtd
uri----http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd
這樣就能不用聯(lián)網(wǎng)就能使用http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd了
3 hibernate
3.1 實(shí)體類編寫
3.1.1 編寫規(guī)則
1) 私有域
2) set-get方法
3) 實(shí)體類有屬性有唯一值
4) 實(shí)體類建議不使用基本類型,使用基本數(shù)據(jù)類型的包裝類
(1) int--Integer,char--Character
(2) 比如表示學(xué)生分?jǐn)?shù)用int就只能表示分?jǐn)?shù)大小,不能使用null表示沒參加,而是用Integer就能解決這個(gè)問題了
3.2 Hibernate主鍵生成策略
1) hibernate要求實(shí)體類厘米嗎必須有一個(gè)屬性作為唯一值,對應(yīng)表主鍵,主鍵可以不同生成策略
2) hibernate主鍵生成策略有很多值
3) 在class里面的值
主要: native,uuid
UUID生成策略的實(shí)體類屬性表id的類型是String類型
private String uid;
<generator>
3.3 Hibernate CRUD
3.3.1 增
User user = new User();
user.setUsername("李四");
user.setPassword("123456");
user.setAddress("上海");
session.save(user);
3.3.2 刪
方法1 查詢-刪除
User user =session.get(User.class , 3);
session.delete(user);
方法2 設(shè)置-刪除
User user = new User();
user.setId(3);
session.delete(user);
3.3.3 改
方法1
方法2 查詢-修改
//李四換成王五
package cn.wanxp.hibernatetest;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.wanxp.entity.User;
import cn.wanxp.utils.HibernateUtils;
public class HibernateDemoDay02 {
@Test
public void testAdd() {
// 直接調(diào)用SessionFactory調(diào)用靜態(tài)調(diào)用方法
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
// (3)使用SessionFactory創(chuàng)建session對象
//類似于JDBC連接
Session session = sessionFactory.openSession();
// (4)開啟事務(wù)
Transaction tx = session.beginTransaction();
// (5)寫具體邏輯編寫CRUD操作
User user = new User();
String username="李四";
user.setUsername(username);
user.setPassword("password1");
user.setAddress("上海");
session.save(user);
System.out.println(user);
user = session.get(User.class , 3);
user.setUsername("王五");
session.update(user);
user = session.get(User.class , 3);
System.out.println(user);
// (6)提交事務(wù)
tx.commit();
// (7)關(guān)閉資源
session.close();
sessionFactory.close();
}
}
3.3.4 查
User user = session.get(User.class,2);//查詢并返回id=2的user
3.3.5 save,update,saveOrUpdate
save:id沒有效果 ,只會(huì)直接添加
update:id的對應(yīng)記錄更新所有內(nèi)容
3.4 實(shí)體類對象狀態(tài)
3.4.1實(shí)體類狀態(tài)三種狀態(tài)
1)瞬時(shí)態(tài),對象里面沒有id值,對象與session沒有關(guān)聯(lián)
User user = new User();
user.setUsername("Jack");
user.setPassword("password");
user.setAddress("上海");
2)持久態(tài),對象里有id值,與session相關(guān)聯(lián)
User user = session.get(User.class , 3);
- 托管態(tài),對象里有id值,與session沒有關(guān)聯(lián)
user.setId(3);
3.4.2演示操作實(shí)體類對象的方法
- saveOrUpdate方法:
- 實(shí)體類狀態(tài)瞬時(shí)態(tài),這個(gè)方法做的是添加操作
- 實(shí)體類狀態(tài)托管態(tài),這個(gè)方法做的是修改操作
- 實(shí)體類狀態(tài)持久態(tài),這個(gè)方法做的是修改操作
4 hibernate的優(yōu)化
4.1 緩存
hibernate有兩級緩存:一級緩存,二級緩存
4.1.1 一級緩存
1)第一類 hibernate一級緩存特點(diǎn)
(1)hibernate的一級緩存默認(rèn)打開的
(2)hibernate的一級緩存適用范圍,是session范圍,從session創(chuàng)建到session關(guān)閉范圍
(3)hibernate的一級緩存中,存儲(chǔ)數(shù)據(jù)必須持久態(tài)數(shù)據(jù)
2)第二類hibernate的二級緩存
(1)目前 已經(jīng)不適用了,替代技術(shù)redis
(2)二級緩存默認(rèn)不是打開的,需要配置
(3)二級緩存使用范圍,是SessionFactory范圍
4.1.2 驗(yàn)證一級緩存的存在
1)驗(yàn)證方式
(1)首先根據(jù)uid=1查詢,返回對象
(2)再次根據(jù)uid=1查詢,返回對象
第二次查詢將不會(huì)查詢數(shù)據(jù)庫而是直接拿出數(shù)據(jù)
4.1.3 一級緩存過程
session.get(),會(huì)先去一級緩存中查詢,若沒有則去數(shù)據(jù)庫,若有直接拿出。
session范圍是指從創(chuàng)建到close();
4.1.4 一級緩存的特點(diǎn)
持久態(tài)會(huì)自動(dòng)執(zhí)行
User user = session.get(User.class , 3);//將對象保存至一級緩存和快照區(qū)
user.setUsername("趙武"); //會(huì)同時(shí)修改:修改user對象里的值,修改持久態(tài)對象的值,修改一級緩存中的內(nèi)容,不會(huì)修改快照區(qū)內(nèi)容
tx.commit();//執(zhí)行到這里即使沒有update,也會(huì)修改數(shù)據(jù)庫
//commit做的內(nèi)容:提交事務(wù),做的事情,比較一級緩存和快照區(qū)內(nèi)容是否相同,若不同則將一級緩存內(nèi)容寫入數(shù)據(jù)庫,若相同則不修改
效果圖如下

4.2 事務(wù)詳解
4.2.1 什么是事務(wù)
4.2.2 事務(wù)的特性
原子性,一致性,隔離性,持久性
4.2.3 不考慮隔離性產(chǎn)生的問題
- 臟讀
2)不可重復(fù)讀
3)虛讀
4.2.4 設(shè)置事務(wù)隔離級別
1)mysql默認(rèn)隔離級別 repeateable read
2)級別設(shè)置 在hibernate.cfg.xml中
<!--
1-Read uncommited isolation
2-Read commited isolation
4-Repeatable read isolation
8-Serializable isolation
-->
<property name="hibernate.connection.isolation">4</property>
4.2.5 hibernate規(guī)范的事務(wù)寫法
try{
//開啟事務(wù)
//提交事務(wù)
}catch(){
//回滾事務(wù)
}final{
//關(guān)閉操作
}
@Test
public void testRollback() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtils.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
User user = session.get(User.class , 3);
user.setUsername("毛毛");
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally{
session.close();
sessionFactory.close();
}
}
4.3 hibernate綁定session線程
4.3.2 介紹
為了保證session是單線程的,而不會(huì)被其它人使用。
注意 由于與本地線程綁定,所以不需要關(guān)閉session了,因?yàn)楸镜鼐€程一完成,session自動(dòng)關(guān)閉
4.3.2 配置
- hibernate.cfg.xml中配置
<property name="hibernate.current_session_context_class">thread</property>
- 調(diào)用SessionFactory對象里的的方法得到
public static Session getSessionObject(){
return sessionFactory.getCurrentSession();
}
5 hibernate的api使用
5.1 查詢
Query對象,Criteria對象 SQLQuery對象
5.1.1 Query對象
1)使用Query對象不需要寫sql語句,但是寫hql語句
(1)hql:hibernate query language,hibernate提供查詢語句
這個(gè)hql語句和普通sql很相似
(2) hql和sql語句區(qū)別
sql操作表和字段
hql操作實(shí)體類和屬性
2)查詢所有hql語句:
(1)from實(shí)體類名稱
3) Query對象使用
(1)創(chuàng)建 Query對象
(2)調(diào)用Query對象里的方法得到結(jié)果
Query query = session.createQuery("from User");
List<User> list = query.list();
5.1.2 Criteria對象
1) Query對象使用
(1)創(chuàng)建 Query對象
(2)調(diào)用Query對象里的方法得到結(jié)果
Criteria criteria = session.createCriteria(User.class);
List<User> list = query.list();
5.1.3 SQLQuery對象
- 使用SQL底層語句
2) SQLQuery對象使用
(1)創(chuàng)建 Query對象
(2)調(diào)用Query對象里的方法得到結(jié)果(默認(rèn)是數(shù)組)
SQLQuer sqlQuery = session.createSQLQuery("select * from t_user where username='張三'");
//默認(rèn)返回的數(shù)組
List list = query.list();
(3)調(diào)用Query對象里的方法得到結(jié)果為對象的做法
SQLQuer sqlQuery = session.createSQLQuery("select * from t_user where username='張三'");
sqlQuery.addEntity(User.class);
List<User> list = query.list();
6 hibernate的表關(guān)系操作
6.1 表的關(guān)系
1)一對多
一個(gè)分類有多個(gè)商品
2)多對多
訂單與商品,一個(gè)訂單多個(gè)商品,一個(gè)商品多個(gè)訂單
3)一對一
丈夫與妻子
6.2 一對多
6.2.1 一對多表創(chuàng)建
1)創(chuàng)建“一”實(shí)體類并在里面創(chuàng)建“多”的Set(集合)如HashSet
2)創(chuàng)建“多”實(shí)體類并在里面創(chuàng)建“一”的實(shí)體的對象作為私有域
3)創(chuàng)建“一”實(shí)體類映射表,將基本的私有域建立好映射
4)創(chuàng)建“多”實(shí)體類映射表,將基本的私有域建立好映射
5)在配置文件中配置一對多關(guān)系
6)創(chuàng)建核心配置文件hibernate.cfg.xml
下面是一個(gè)例子,客戶(企業(yè))類,每個(gè)(客戶)企業(yè)都有很多員工的聯(lián)系方式,客戶表-員工聯(lián)系方式表就是一對多的關(guān)系
①----客戶實(shí)體類 Customer.java
package cn.wanxp.entity;
import java.util.HashSet;
import java.util.Set;
public class Customer {
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public String getCustomerLevel() {
return customerLevel;
}
public void setCustomerLevel(String customerLevel) {
this.customerLevel = customerLevel;
}
public String getCustomerSource() {
return customerSource;
}
public void setCustomerSource(String customerSource) {
this.customerSource = customerSource;
}
public String getCustomerPhone() {
return customerPhone;
}
public void setCustomerPhone(String customerPhone) {
this.customerPhone = customerPhone;
}
public String getCustomerMobile() {
return customerMobile;
}
public void setCustomerMobile(String customerMobile) {
this.customerMobile = customerMobile;
}
//在客戶實(shí)體類中表示多個(gè)聯(lián)系人,一個(gè)客戶對應(yīng)多個(gè)聯(lián)系人
//hibernate要求使用集合表示多的數(shù)據(jù),使用Set集合
private Set<Linkman> setLinkman = new HashSet<Linkman>();
public Set<Linkman> getSetLinkman() {
return setLinkman;
}
public void setSetLinkman(Set<Linkman> setLinkman) {
this.setLinkman = setLinkman;
}
private Integer cid;
private String customerName;
private String customerLevel;
private String customerSource;
private String customerPhone;
private String customerMobile;
}
②----”多“的表實(shí)體類Linkman.java
package cn.wanxp.entity;
public class Linkman {
public Integer getLid() {
return lid;
}
public void setLid(Integer lid) {
this.lid = lid;
}
public String getLinkmanName() {
return linkmanName;
}
public void setLinkmanName(String linkmanName) {
this.linkmanName = linkmanName;
}
public String getLinkmanGender() {
return linkmanGender;
}
public void setLinkmanGender(String linkmanGender) {
this.linkmanGender = linkmanGender;
}
public String getLinkmanPhone() {
return linkmanPhone;
}
public void setLinkmanPhone(String linkmanPhone) {
this.linkmanPhone = linkmanPhone;
}
//在聯(lián)系人實(shí)體類里表示所屬客戶,一個(gè)聯(lián)系人屬于一個(gè)客戶
private Customer customer = new Customer();
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
private Integer lid;
private String linkmanName;
private String linkmanGender;
private String linkmanPhone;
}
③----Customer實(shí)體配置文件Customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="cn.wanxp.entity.Customer" table="t_customer">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="customerName" column="customerName"></property>
<property name="customerLevel" column="customerLevel"></property>
<property name="customerSource" column="customerSource"></property>
<property name="customerPhone" column="customerPhone"></property>
<property name="customerMobile" column="customerMobile"></property>
<!-- 在客戶映射文件中,表示所有聯(lián)系人,使用set標(biāo)簽表示所有聯(lián)系人
set標(biāo)簽里面有name屬性:屬性值寫在客戶實(shí)體類里面表示聯(lián)系惡人的set集合名稱
-->
<set name="setLinkman">
<!-- 一對多建表,有外鍵。hibernate機(jī)制:雙向維護(hù)外鍵,在一和多都有配置外鍵
column屬性值:外鍵名稱
-->
<key column="cid"></key>
<one-to-many class="cn.wanxp.entity.Linkman"/>
</set>
</class>
</hibernate-mapping>
④----Linkman配置文件 Linkman.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="cn.wanxp.entity.Linkman" table="t_linkman">
<id name="lid" column="lid">
<generator class="native"></generator>
</id>
<property name="linkmanName" column="linkmanName"></property>
<property name="linkmanGender" column="linkmanGender"></property>
<property name="linkmanPhone" column="linkmanPhone"></property>
<!-- 在聯(lián)系人中配置所屬客戶
name屬性:因?yàn)樵诼?lián)系人實(shí)體類使用Customer對象表示。寫customer名稱
class屬性:Customer全路徑
column屬性是生成的表格存儲(chǔ)Customer的id的列名稱要與Customer.hbm.xml中key一致
-->
<many-to-one name="customer" class="cn.wanxp.entity.Customer" column="cid"></many-to-one>
</class>
</hibernate-mapping>
⑤----同樣需要將配置文件加入到hibernate核心配置文件中
<mapping resource="/cn/wanxp/entity/Customer.hbm.xml" />
<mapping resource="/cn/wanxp/entity/Linkman.hbm.xml" />
⑥----測試效果
package cn.wanxp.hibernatetest;
import java.io.UnsupportedEncodingException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import cn.wanxp.entity.User;
public class HibernateDemoDay03 {
@Test
public void testOneToMany() {
Configuration cfg = new Configuration();
cfg.configure();
SessionFactory sessionFactory=cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
tx.commit();
session.close();
sessionFactory.close();
}
}
⑦----輸出結(jié)果
Hibernate:
create table t_customer (
cid integer not null auto_increment,
customerName varchar(255),
customerLevel varchar(255),
customerSource varchar(255),
customerPhone varchar(255),
customerMobile varchar(255),
primary key (cid)
) engine=MyISAM
Hibernate:
create table t_linkman (
lid integer not null auto_increment,
linkmanName varchar(255),
linkmanGender varchar(255),
linkmanPhone varchar(255),
cid integer,
primary key (lid)
) engine=MyISAM
Hibernate:
alter table t_linkman
add constraint FKn4dw5i2knad5dl95xit4v1b0p
foreign key (cid)
references t_customer (cid)
6.2.1 一對多表操作
1)一對多級聯(lián)保存 -- 復(fù)雜寫法
直接在session中設(shè)置并保存
package cn.wanxp.hibernatetest;
import java.io.UnsupportedEncodingException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import cn.wanxp.entity.Customer;
import cn.wanxp.entity.Linkman;
import cn.wanxp.entity.User;
import cn.wanxp.utils.HibernateUtils;
public class HibernateDemoDay03 {
@Test
public void testOneToManyAdd() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
Customer customer = new Customer();
Linkman linkman = new Linkman();
try {
sessionFactory = HibernateUtils.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//1創(chuàng)建客戶和聯(lián)系人對象并設(shè)置基本域值
linkman.setLinkmanName("李四");
linkman.setLinkmanGender("男");
linkman.setLinkmanPhone("131313");
customer.setCustomerName("聯(lián)想");
customer.setCustomerSource("web");
customer.setCustomerLevel("vip");
customer.setCustomerPhone("3333");
customer.setCustomerMobile("1111");
//2在客戶表中和聯(lián)系人表中連接部分分別添加對方
linkman.setCustomer(customer);
customer.getSetLinkman().add(linkman);
//3使用save存儲(chǔ)進(jìn)數(shù)據(jù)表中
session.save(customer);
session.save(linkman);
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
}
2)一對多級聯(lián)保存 -- 簡單寫法
第一步在客戶映射文件中進(jìn)行配置
修改Customer.hbm.xml配置文件中的set標(biāo)簽,在set標(biāo)簽中添加 cascade="save-update"屬性
<set name="setLinkman" cascade="save-update">
上面的HibernateDemoDay03.java就可以修改為
package cn.wanxp.hibernatetest;
import java.io.UnsupportedEncodingException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import cn.wanxp.entity.Customer;
import cn.wanxp.entity.Linkman;
import cn.wanxp.entity.User;
import cn.wanxp.utils.HibernateUtils;
public class HibernateDemoDay03 {
@Test
public void testOneToManyAdd() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
Customer customer = new Customer();
Linkman linkman = new Linkman();
try {
sessionFactory = HibernateUtils.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//1創(chuàng)建客戶和聯(lián)系人對象并設(shè)置基本域值
linkman.setLinkmanName("李四");
linkman.setLinkmanGender("男");
linkman.setLinkmanPhone("131313");
customer.setCustomerName("聯(lián)想");
customer.setCustomerSource("web");
customer.setCustomerLevel("vip");
customer.setCustomerPhone("3333");
customer.setCustomerMobile("1111");
//2在客戶表中添加聯(lián)系人實(shí)體類對象,相互
linkman.setCustomer(customer);
customer.getSetLinkman().add(linkman);
//3使用save存儲(chǔ)進(jìn)數(shù)據(jù)表中
session.save(customer);
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
}
效果如下

3)一對多刪除
如,刪除某個(gè)客戶,把客戶里面所有的聯(lián)系人刪除
① 在客戶映射文件中進(jìn)行配置(多個(gè)值用逗號隔開)
修改Customer.hbm.xml配置文件中的set標(biāo)簽,在set標(biāo)簽中添加 cascade="save-update,delete"屬性
<set name="setLinkman" cascade="save-update,delete">
② 在代碼中直接刪除
先根據(jù)id查找客戶然后刪除
@Test
public void testOneToManyDelete() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
Customer customer = new Customer();
Linkman linkman = new Linkman();
try {
sessionFactory = HibernateUtils.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
customer = session.get(Customer.class, 1);
session.delete(customer);
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
效果如下

3)一對多修改
(1)如將多方的ABC三個(gè)記錄中的C的外鍵Y修改為一方的XY中的X
Customer X=session.get(Customer.class,1);
Linkman C=session.get(Linkman.class,3);
X.getSetLinkman().add(C);
(2)一對多的里面,可以讓其中一方放棄維護(hù),用以提高效率。一般讓一放棄維護(hù),多的維護(hù)
(3)具體實(shí)現(xiàn)放棄維護(hù)
set標(biāo)簽中的inverse屬性:放棄true,不放棄false(默認(rèn))
<set name="setLinkman" inverse="true" cascade="save-update,delete">
6.2.2 多對多表
- 多對多映射配置
(1)創(chuàng)建實(shí)體類,用戶和角色
Person.java
package cn.wanxp.entity;
import java.util.HashSet;
import java.util.Set;
public class Person {
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Role> getSetRole() {
return setRole;
}
public void setSetRole(Set<Role> setRole) {
this.setRole = setRole;
}
private Integer pid;
private String name;
private Set<Role> setRole = new HashSet<Role>();
}
Role.java
package cn.wanxp.entity;
import java.util.HashSet;
import java.util.Set;
public class Role {
public Integer getRid() {
return rid;
}
public void setRid(Integer rid) {
this.rid = rid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Person> getSetPerson() {
return setPerson;
}
public void setSetPerson(Set<Person> setPerson) {
this.setPerson = setPerson;
}
private Integer rid;
private String name;
private Set<Person> setPerson = new HashSet<Person>();
}
(2)讓兩個(gè)實(shí)體類之間相互表示
①用戶里表示所有角色,使用set集合
②一個(gè)角色有多個(gè)用戶,使用set集合
(3)配置映射
①基本配置
②配置多對多關(guān)系
person.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="cn.wanxp.entity.Person" table="t_person">
<id name="pid" column="pid">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<!-- 在客戶映射文件中,表示所有聯(lián)系人,使用set標(biāo)簽表示所有聯(lián)系人
set標(biāo)簽里面有name屬性:屬性值寫在客戶實(shí)體類里面表示聯(lián)系惡人的set集合名稱
table:第三張表名
-->
<set name="setRole" table="t_person_role" cascade="all">
<!-- 一對多建表,有外鍵。hibernate機(jī)制:雙向維護(hù)外鍵,在一和多都有配置外鍵
key屬性 column當(dāng)前映射文件在第三張表的外鍵名稱
-->
<key column="person_id"></key>
<!-- 一對多建表,有外鍵。hibernate機(jī)制:雙向維護(hù)外鍵,在一和多都有配置外鍵
many-to-many屬性 column值Role在第三張表的外鍵名稱
-->
<many-to-many class="cn.wanxp.entity.Role" column="role_id" />
</set>
</class>
</hibernate-mapping>
role.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="cn.wanxp.entity.Role" table="t_role">
<id name="rid" column="rid">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<!-- 在客戶映射文件中,表示所有聯(lián)系人,使用set標(biāo)簽表示所有聯(lián)系人
set標(biāo)簽里面有name屬性:屬性值寫在客戶實(shí)體類里面表示聯(lián)系惡人的set集合名稱
-->
<set name="setPerson" table="t_person_role" cascade="all">
<!--
key屬性 column當(dāng)前映射文件在第三張表的外鍵名稱
-->
<key column="role_id"></key>
<!-- 一對多建表,有外鍵。hibernate機(jī)制:雙向維護(hù)外鍵,在一和多都有配置外鍵
many-to-many屬性 column值Person在第三張表的外鍵名稱
-->
<many-to-many class="cn.wanxp.entity.Person" column="person_id"/>
</set>
</class>
</hibernate-mapping>
--在用戶里表示所有角色,使用set標(biāo)簽
--在角色里表示所有用戶,使用set標(biāo)簽
(4)核心配置中引入配置文件
2)多對多級聯(lián)保存
public void testManyToManyAdd() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtils.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
//創(chuàng)建對象
Person p1 = new Person();
Person p2 = new Person();
p1.setName("張三");
p2.setName("李四");
Role r1 = new Role();
Role r2 = new Role();
Role r3 = new Role();
r1.setName("肉坦");
r2.setName("輸出");
r3.setName("輔助");
//關(guān)聯(lián)對象
p1.getSetRole().add(r1);
p2.getSetRole().add(r2);
p1.getSetRole().add(r3);
//保存對象
session.save(p1);
session.save(p2);
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
效果如下

3)多對多級聯(lián)刪除
刪除方式同一對多刪除
4)維護(hù)第三張表關(guān)系
用戶表添加角色 搜索用戶表,搜索角色表,在用戶表中添加角色,如p1.getSetRole().add(r5);
用戶表刪除角色 搜索用戶表,搜索角色表,在用戶表中刪除角色,如p1.getSetRole().remove(r2);
7 hibernate 查詢方式
7.1 對象導(dǎo)航查詢
如一對多表格 客戶與聯(lián)系人,根據(jù)某個(gè)id查詢 客戶以及下面的聯(lián)系人
先按照id搜索客戶,然后獲取set集合即可
Customer customer = session.get(Customer.class , 1);
Set<Linkman> setLinkman = customer.getSetlinkman();
7.2 OID查詢
根據(jù)id查詢某一條記錄
按照id搜索客戶
Customer customer = session.get(Customer.class , 1);
7.3 hql查詢
Query對象,寫hql語句查詢
hql與sql類似
區(qū)別:hql操作實(shí)體類和屬性,sql操作數(shù)據(jù)庫表和字段
過程:創(chuàng)建Query對象,寫hql語句 ,調(diào)用Query對象的方法獲得結(jié)果
7.3.1 查詢所有
//from 實(shí)體類名稱
Query query = session.createQuery("from Customer");
//調(diào)用方法得到結(jié)果
List<Customer> list = query.list();
7.3.2 條件查詢
//from 實(shí)體類名稱 where 實(shí)體類屬性名稱=? [and 實(shí)體類屬性名稱=? ...] 或者 from 實(shí)體類名稱 實(shí)體類屬性名稱 like ?
Query query = session.createQuery("from Customer c where c.cid=? and c.customerName=?");
//問好問號位置從0開始
query.setParameter(0,1);
query.setParameter(1,"百度");
//調(diào)用方法得到結(jié)果
List<Customer> list = query.list();
7.3.3 排序查詢
//在上面基礎(chǔ)上 加入 order by 實(shí)體類屬性名稱 desc|asc (desc 降序,asc 升序)
Query query = session.createQuery("from Customer c where c.cid=? and c.customerName=?" order by c.cid desc);
7.3.4 分頁查詢
Query query = session.createQuery("from Customer");
//設(shè)置起始位置
query.setFirstResult(0);
//設(shè)置每頁記錄數(shù)量
query.setMaxResult(3);
//調(diào)用方法得到結(jié)果
List<Customer> list = query.list();
7.3.5 投影查詢
sql:select customerName from Customer; --查詢部分字段而不是所有字段
Query query = session.createQuery("select customerName from Customer");
list<Object> list = query.list();//注意這里的區(qū)別
7.3.6 聚集函數(shù)使用
常用count sum avg max min
//hql:select count(*) from 實(shí)體類名
Query query = session.createQuery(" select count(*) from Customer");
Object obj = query.uniqueResult();
7.4 QBC查詢
1)使用hql需要寫hql語句,但使用qbc是不需要寫語句,只需要方法就行
2)使用qbc操作實(shí)體類和屬性
3)使用Criteria對象進(jìn)行操作
7.4.1 查詢所有
//創(chuàng)建Criteria對象
Criteria criteria = session.createCriteria(Customer.class);
//調(diào)用Criteria對象的方法
List<Customer> list = criteria.list();
7.4.2 條件查詢
//創(chuàng)建Criteria對象
Criteria criteria = session.createCriteria(Customer.class);
//調(diào)用Criteria對象的方法設(shè)置條件
//add方法添加條件,參數(shù)Restrictions對象的方法,方法里傳入實(shí)體類屬性和值
criteria.add(Restrictions.eq("cid",1));
List<Customer> list = criteria.list();
7.4.3 排序查詢
//創(chuàng)建Criteria對象
Criteria criteria = session.createCriteria(Customer.class);
//調(diào)用Criteria對象的方法設(shè)置條件
//addOrder方法添加條件,參數(shù)Order對象的方法,方法里傳入實(shí)體類屬性asc升序desc降序
criteria.addOrder(Order.asc("cid"));
List<Customer> list = criteria.list();
7.4.4 分頁查詢
//創(chuàng)建Criteria對象
Criteria criteria = session.createCriteria(Customer.class);
//調(diào)用Criteria對象的方法設(shè)置條件
//setFirstResult(0)起始位置0,setMaxResult(3)獲得3條記錄
criteria.setFirstResult(0);
criteria.setMaxResult(3);
List<Customer> list = criteria.list();
7.4.5 統(tǒng)計(jì)查詢
//創(chuàng)建Criteria對象
Criteria criteria = session.createCriteria(Customer.class);
//調(diào)用Criteria對象的方法設(shè)置條件
criteria.setProjection(Projections.rowCount());
Object obj = criteria.uniqueResult();
Long lobj = (Long) obj
int count = lobj.intValue();
System.out.println(count);
7.4.5 離線查詢
//創(chuàng)建DetachedCriteria對象
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List<Customer> list = criteria.list();
7.5 本地sql查詢
SQLQuery對象,使用普通sql實(shí)現(xiàn)
8 多表查詢
8.1 內(nèi)連接
8.1.1 內(nèi)連接
sql語句:select * from t_customer as c inner join t_linkman as l on c.cid=l.lid;
Query query = session.createQuery("from Customer c inner join c.setLinkman");
//list()返回的Object對象的數(shù)字
List list = query.list();
8.1.2 迫切內(nèi)連接
1)與內(nèi)連接底層是一樣的
2)區(qū)別:使用內(nèi)連接返回list中每部分是數(shù)組,迫切內(nèi)連接返回的是對象
用法:加入關(guān)鍵字fetch
Query query = session.createQuery("from Customer c inner join fetch c.setLinkman");
//list()返回的Object對象的數(shù)字
List list = query.list();
8.2 左外連接
8.2.1 左外連接
sql語句:select * from t_customer as c left outer join t_linkman as l on c.cid=l.lid;
Query query = session.createQuery("from Customer c left outer join c.setLinkman");
//list()返回的Object對象的數(shù)字
List list = query.list();
8.2.2 迫切左外連接
效果用法區(qū)別與內(nèi)連接類似
8.3 右外連接
8.3.1 右外連接
sql語句:select * from t_customer as c right outer join t_linkman as l on c.cid=l.lid;
Query query = session.createQuery("from Customer c right outer join c.setLinkman");
//list()返回的Object對象的數(shù)字
List list = query.list();
8.3.2 迫切右外連接
效果用法區(qū)別與內(nèi)連接類似
9 hibernate檢索策略
9.1 立即查詢
如根據(jù)id查詢,調(diào)用get方法時(shí),一調(diào)用get方法立即發(fā)送查詢語句給數(shù)據(jù)庫
9.2 延遲查詢
如根據(jù)id查詢,調(diào)用load方法時(shí),調(diào)用load方法,不會(huì)立即發(fā)送查詢語句給數(shù)據(jù)庫,只有得到對象里面的值時(shí)才會(huì)發(fā)送查詢語句
分類:類級別延遲,關(guān)聯(lián)級別延遲
9.2.1 類級別延遲
就是上面那種
9.2.2 關(guān)聯(lián)類級別延遲
如查詢Customer時(shí),是否延遲查詢關(guān)聯(lián)的Linkman
默認(rèn)狀態(tài)
Customer customer = session.get(Customer.class , 1);
//執(zhí)行到這里時(shí),只發(fā)送了查詢表t_customer
Set<Linkman> setLinkman = customer.getSetlinkman();
//執(zhí)行到這里時(shí),只發(fā)送了查詢表t_customer
System.out.println(list.size());//執(zhí)行到這里將會(huì)發(fā)送查詢t_linkman表命令
修改延遲
在set標(biāo)簽上修改屬性
fetch :值select
lazy:值
----true:延遲,默認(rèn)
----false:不延遲
----extra:極其延遲,要什么值就去查什么值
10 批量查詢
如獲取所有客戶的聯(lián)系人
方式1 普通方式,效率較低
//下面這種方式經(jīng)過測試效率不高,因?yàn)槊看尾樵円粭l客戶再查詢聯(lián)系人都要發(fā)送查詢命令
Criteria criteria =session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
for(Customer customer:list){
Systerm.out.println(customer.getId());
Set setLinkman =customer.getSetLinkman();
for(Linkman linkman : setLinkman){
System.out.println(linkman.getId());
}
}
方式2 修改配置Customer文件 ,在set標(biāo)簽中加入屬性batch-size,batch-size的值只要是整數(shù)即可,其值越大,發(fā)送的語句命令越少,效率越高
<set name = "setLinkman" batch-size="2">