配套資料,免費下載
連結:https://pan.baidu.com/s/1i_RXtOyN1e4MMph6V7ZF-g
提取碼:8dw6
複製這段內容後開啟百度網盤手機App,操作更方便哦
第一章 Hibernate5快速入門
1.1、Hibernate5概述
Hibernate是一個開放原始碼的ORM(Object Relational Mapping,物件關係對映)框架,它對JDBC進行了非常輕量級的物件封裝,它將POJO與資料庫表建立對映關係,Hibernate可以自動生成SQL語句並執行,使得Java程式設計師可以隨心所欲的使用物件導向程式設計思維來操縱資料庫。 Hibernate可以應用在任何使用JDBC的場合,既可以在Java的客戶端程式使用,也可以在Servlet/JSP的Web應用中使用,最具革命意義的是,Hibernate可以在應用EJB的JaveEE架構中取代CMP,完成資料持久化的重任。
1.2、Hibernate5下載
官方網址:hibernate orm
目錄介紹:
hibernate-release-5.0.7.Final資料夾介紹:
hibernate-release-5.0.7.Final\lib資料夾介紹:
1.3、Hibernate5工程搭建
把下面四個資料夾的內容全部拷貝到lib中
- hibernate-release-5.0.7.Final\lib\required
- hibernate-release-5.0.7.Final\lib\optional\c3p0
- 日誌記錄包
- 資料庫驅動
把下面四個資料夾的內容全部拷貝到lib中後,全部選中,右鍵Build Path一下
將日誌記錄配置檔案複製到src中,並在src中建立com.caochenlei.hibernate.demo包,用於存放測試程式碼
由於我們需要進行單元測試,於是乎,我們需要給現在這個工程新增一個Junit4的依賴,具體操作如下圖:
Java工程搭建好了以後,我們需要有一個資料庫(mytest)和一張表(cst_customer)用於測試:
CREATE TABLE `cst_customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(主鍵)',
`cust_name` varchar(32) NOT NULL COMMENT '客戶名稱',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客戶資訊來源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客戶所屬行業',
`cust_level` varchar(32) DEFAULT NULL COMMENT '客戶級別',
`cust_phone` varchar(64) DEFAULT NULL COMMENT '固定電話',
`cust_mobile` varchar(16) DEFAULT NULL COMMENT '行動電話',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
到此,準備工作就完成了,接下來就是我們的程式設計了
1.4、Hibernate5測試程式碼
Customer.java(全路徑:/hibernate_demo/src/com/caochenlei/hibernate/demo/Customer.java)
package com.caochenlei.hibernate.demo;
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry(String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level() {
return cust_level;
}
public void setCust_level(String cust_level) {
this.cust_level = cust_level;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
@Override
public String toString() {
return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + ", cust_source=" + cust_source
+ ", cust_industry=" + cust_industry + ", cust_level=" + cust_level + ", cust_phone=" + cust_phone
+ ", cust_mobile=" + cust_mobile + "]";
}
}
Customer.hbm.xml(全路徑:/hibernate_demo/src/com/caochenlei/hibernate/demo/Customer.hbm.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 建立類與表的對映關係 -->
<class name="com.caochenlei.hibernate.demo.Customer" table="cst_customer">
<!-- 設定主鍵欄位對映 -->
<id name="cust_id" column="cust_id">
<generator class="native" />
</id>
<!-- 設定普通欄位對映 -->
<property name="cust_name" column="cust_name" />
<property name="cust_source" column="cust_source" />
<property name="cust_industry" column="cust_industry" />
<property name="cust_level" column="cust_level" />
<property name="cust_phone" column="cust_phone" />
<property name="cust_mobile" column="cust_mobile" />
</class>
</hibernate-mapping>
hibernate.cfg.xml(全路徑:/hibernate_demo/src/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>
<!-- 資料庫的配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/mytest</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.isolation">4</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<!-- 資料庫連線池 -->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="c3p0.min_size">5</property>
<property name="c3p0.max_size">20</property>
<property name="c3p0.timeout">120</property>
<property name="c3p0.idle_test_period">3000</property>
<!-- 其它的可選項 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 載入對映檔案 -->
<mapping resource="com/caochenlei/hibernate/demo/Customer.hbm.xml" />
</session-factory>
</hibernate-configuration>
CustomerTest.java(全路徑:/hibernate_demo/src/com/caochenlei/hibernate/demo/CustomerTest.java)
package com.caochenlei.hibernate.demo;
import java.util.Arrays;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class CustomerTest {
@Test
public void testInsert() {
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("李四");
session.save(customer);
tx.commit();
session.close();
}
@Test
public void testDelete() {
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_id(1L);
session.delete(customer);
tx.commit();
session.close();
}
@Test
public void testUpdate() {
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_id(2L);
customer.setCust_name("張三");
session.update(customer);
tx.commit();
session.close();
}
@Test
public void testSaveOrUpdate() {
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
// 如果存在id就意味著更新,如果不存在id就意味著插入
// customer.setCust_id(6L);
customer.setCust_name("張三");
session.saveOrUpdate(customer);
tx.commit();
session.close();
}
@Test
public void testGet() {
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = session.get(Customer.class, 4L);
System.out.println(customer);
tx.commit();
session.close();
}
@Test
public void testLoad() {
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = session.load(Customer.class, 4L);
System.out.println(customer);
tx.commit();
session.close();
}
@SuppressWarnings("unchecked")
@Test
public void testQuery() {
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("from Customer");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
session.close();
}
@SuppressWarnings("unchecked")
@Test
public void testSQLQuery() {
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list = sqlQuery.list();
for (Object[] customer : list) {
System.out.println(Arrays.toString(customer));
}
tx.commit();
session.close();
}
}
1.5、Hibernate5工具類
通過上邊的程式碼我們不難發現,很多程式碼都是重複的,這無疑增加了我們開發時程式碼量,所以我們需要將能抽取的部分抽取出來,由於Configuration和SessionFactory是執行緒安全的,且一個工程只需要有一個即可,所以我們把這一部分抽取出來,而Session是執行緒不安全的,我們不能抽取,只能使用區域性變數的方式訪問才不會出現執行緒安全的問題
HibernateUtil.java(全路徑:/hibernate_demo/src/com/caochenlei/hibernate/utils/HibernateUtil.java)
package com.caochenlei.hibernate.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static Configuration configuration = null;
private static SessionFactory sessionFactory = null;
static {
configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}
/**
* 會話獨立,需要關閉
* @return
*/
public static Session openSession() {
return sessionFactory.openSession();
}
/**
* 會話繫結,無需關閉
* @return
*/
public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
第二章 Hibernate5核心配置
2.1、兩種配置方式
2.1.1、屬性檔案的方式(瞭解)
hibernate.properties(全路徑:/hibernate_demo/src/hibernate.properties)
#資料庫的配置
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://127.0.0.1:3306/mytest
hibernate.connection.username=root
hibernate.connection.password=root
hibernate.connection.isolation=4
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.current_session_context_class=thread
#資料庫連線池
connection.provider_class=org.hibernate.connection.C3P0ConnectionProvider
c3p0.min_size=5
c3p0.max_size=20
c3p0.timeout=120
c3p0.idle_test_period=3000
#其它的可選項
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.hbm2ddl.auto=update
CustomerPropertiesTest.java(全路徑:/hibernate_demo/src/com/caochenlei/hibernate/demo/CustomerPropertiesTest.java)
package com.caochenlei.hibernate.demo;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class CustomerPropertiesTest {
@Test
public void testMethod() {
try {
Configuration configuration = new Configuration();
Properties properties = new Properties();
InputStream inStream = getClass().getClassLoader().getResourceAsStream("hibernate.properties");
properties.load(inStream);
configuration.addProperties(properties);
configuration.addResource("com/caochenlei/hibernate/demo/Customer.hbm.xml");
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("王五");
session.save(customer);
tx.commit();
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.1.2、xml檔案的方式(掌握)
hibernate.cfg.xml(全路徑:/hibernate_demo/src/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>
<!-- 資料庫的配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/mytest</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.isolation">4</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<!-- 資料庫連線池 -->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="c3p0.min_size">5</property>
<property name="c3p0.max_size">20</property>
<property name="c3p0.timeout">120</property>
<property name="c3p0.idle_test_period">3000</property>
<!-- 其它的可選項 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 載入對映檔案 -->
<mapping resource="com/caochenlei/hibernate/demo/Customer.hbm.xml" />
</session-factory>
</hibernate-configuration>
CustomerXMLTest.java(全路徑:/hibernate_demo/src/com/caochenlei/hibernate/demo/CustomerXMLTest.java)
package com.caochenlei.hibernate.demo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class CustomerXMLTest {
@Test
public void testMethod() {
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("小七");
session.save(customer);
tx.commit();
session.close();
}
}
2.2、核心配置講解
2.2.1、核心的配置
- 資料庫的配置
- hibernate.connection.driver_class:資料庫驅動名稱
- hibernate.connection.url:資料庫連線地址
- hibernate.connection.username:資料庫賬戶
- hibernate.connection.password:資料庫密碼
- hibernate.dialect:資料庫方言
- MySQL方言:org.hibernate.dialect.MySQLDialect
- Oracle方言:org.hibernate.dialect.Oracle10gDialect
- SQL Server方言:org.hibernate.dialect.SQLServerDialect
- hibernate.connection.isolation:資料庫隔離級別
- 0:TRANSACTION_NONE
- 1:TRANSACTION_READ_UNCOMMITTED
- 2:TRANSACTION_READ_COMMITTED(Oracle常用)
- 4:TRANSACTION_REPEATABLE_READ(MySQL常用)
- 8:TRANSACTION_SERIALIZABLE
- hibernate.current_session_context_class:獲取當前會話的上下文
- thread:物件的生命週期與本地執行緒繫結(常用)
- jta:物件的生命週期與JTA事務繫結
- managed:委託程式來管理session的生命週期
- 資料庫連線池
- connection.provider_class:設定資料庫連線池提供方,一般使用C3P0
- c3p0.min_size:在連線池中可用的資料庫連線的最少數目
- c3p0.max_size:在連線池中可用的資料庫連線的最大數目
- c3p0.timeout:設定資料庫連線的過期時間,以秒為單位
- c3p0.idle_test_period:每隔多少秒檢查連線池中的空閒連線,以秒為單位
- 其它的可選項
- hibernate.show_sql:顯示sql語句
- hibernate.format_sql:格式化sql語句
- hibernate.hbm2ddl.auto:是否自動建表
- none:不使用hibernate的自動建表
- create:如果資料庫中已經有表,刪除原有表,重新建立,如果沒有表,新建表。(測試)
- create-drop:如果資料庫中已經有表,刪除原有表,重新建立,然後執行操作,刪除這個表。如果沒有表,新建一個,使用完了刪除該表。(測試)
- update:如果資料庫中有表,使用原有表,如果資料庫中沒有表,建立新表。(可以自動更新表結構,常用)
- validate:如果資料庫中沒有表,不會建立表,只會使用資料庫中原有的表。(可以校驗對映和表結構,常用)
- 載入對映檔案
- <mapping resource="包名.類名.hbm.xml" />
2.2.2、對映的配置
-
class標籤的配置:用來建立類與表的對映關係
- name:類的全路徑
- table:表名(類名與表名一致,table可以省略)
- catalog:資料庫名(可以省略)
-
id標籤的配置:用來建立類中的屬性與表中的主鍵的對應關係
- name:類中的屬性名
- column:表中的欄位名(類中的屬性名和表中的欄位名如果一致,column可以省略)
- length:長度(用於自動建表的時候指定資料的長度,如果不指定則使用預設值,可以省略)
- type:型別(用於自動建表的時候指定資料的型別,如果不指定,Hibernate可以自動幫你轉換,可以省略)
- 第一種:Java中的型別,例如:java.lang.String
- 第二種:Hibernate中的型別,例如:string
- 第三種:sql中的型別,需要把column屬性去掉,在property中寫一個子標籤<column name="表中的欄位名" sql-type="varchar"></column>
主鍵的生成策略如下:
- increment:使用的是hibernate中提供的自動增長機制(先查詢id最大值,然後再加1),適用於short、int、long型別的主鍵,在單執行緒中使用
- identity:使用的是資料庫底層的自動增長機制(設定主鍵的AUTO_INCREMENT),適用於short、int、long型別的主鍵,在單執行緒/多執行緒中使用,適用於Mysql、Sql Server,但不適用於Oracle
- sequence:使用的是序列方式,適用於short、int、long型別的主鍵,在單執行緒/多執行緒中使用,不適用於Mysql、Sql Server,但適用於Oracle
- native:本地策略,可以智慧的在identity和sequence之間進行切換
- uuid:使用的是hibernate中的隨機方式生成字串主鍵,適用於字串型別的主鍵
- assigned:hibernate放棄外來鍵的管理,通過開發者自己編寫程式來控制
-
property標籤的配置:用來建立類中的普通屬性與表的欄位的對應關係
- name:類中的屬性名
- column:表中的欄位名(類中的屬性名和表中的欄位名如果一致,column可以省略)
- length:長度(用於自動建表的時候指定資料的長度,如果不指定則使用預設值,可以省略)
- type:型別(用於自動建表的時候指定資料的型別,如果不指定,Hibernate可以自動幫你轉換,可以省略)
- 第一種:Java中的型別,例如:java.lang.String
- 第二種:Hibernate中的型別,例如:string
- 第三種:sql中的型別,需要把column屬性去掉,在property中寫一個子標籤<column name="表中的欄位名" sql-type="varchar"></column>
- not-null:設定非空
- unique:設定唯一
2.3、核心物件講解
Hibernate的API一共有6個,分別為:Configuration、SessionFactory、Session、Transaction、Query、Criteria。通過這些介面,可以對持久化物件進行存取、事務控制。
2.3.1、Configuration
Configuration 類的作用是對Hibernate 進行配置,以及對它進行啟動。在Hibernate 的啟動過程中,Configuration 類的例項首先定位對映文件的位置,讀取這些配置,然後建立一個SessionFactory物件。雖然Configuration 類在整個Hibernate 專案中只扮演著一個很小的角色,但它是啟動Hibernate 時所遇到的第一個物件。
2.3.2、SessionFactory
SessionFactory介面負責初始化Hibernate。它充當資料儲存源的代理,並負責建立Session物件。這裡用到了工廠模式。需要注意的是SessionFactory並不是輕量級的,因為一般情況下,一個專案通常只需要一個SessionFactory就夠,當需要操作多個資料庫時,可以為每個資料庫指定一個SessionFactory。
2.3.3、Session
Session介面負責執行被持久化物件的CRUD操作(CRUD的任務是完成與資料庫的交流,包含了很多常見的SQL語句)。但需要注意的是Session物件是非執行緒安全的。同時,Hibernate的session不同於JSP應用中的HttpSession。這裡當使用session這個術語時,其實指的是Hibernate中的session,而以後會將HttpSession物件稱為使用者session。
2.3.4、Transaction
Transaction 介面是一個可選的API,可以選擇不使用這個介面,取而代之的是Hibernate 的設計者自己寫的底層事務處理程式碼。Transaction 介面是對實際事務實現的一個抽象,這些實現包括JDBC的事務、JTA 中的UserTransaction、甚至可以是CORBA 事務。之所以這樣設計是能讓開發者能夠使用一個統一事務的操作介面,使得自己的專案可以在不同的環境和容器之間方便地移植。
2.3.5、Query
Query介面讓你方便地對資料庫及持久物件進行查詢,它可以有兩種表達方式:HQL語言或本地資料庫的SQL語句。Query經常被用來繫結查詢引數、限制查詢記錄數量,並最終執行查詢操作。
2.3.6、Criteria
Criteria介面與Query介面非常類似,允許建立並執行物件導向的標準化查詢。值得注意的是Criteria介面也是輕量級的,它不能在Session之外使用。
第三章 Hibernate5持久化類
3.1、持久化類的概述
持久化:將記憶體中的物件持久化到資料庫中的過程,而Hibernate就是用來完成持久化的框架
持久化類:一個Java物件與資料庫的表建立了對映關係,那麼這個類在Hibernate中稱為持久化類,簡而言之:持久化類 = Java類 + 對映檔案
3.2、持久化類的規則
- 對持久化類提供無參構造方法
- 讓持久化類的屬性私有化,對私有屬性提供public的get或者set方法
- 讓持久化類中的屬性儘量使用包裝型別而不是基本型別
- 對持久化類提供一個唯一標識OID與資料庫主鍵對應
- 對持久化類不能使用final修飾
3.3、持久化類的狀態
持久化類一共有三種不同的狀態,它們分別如下:
- 瞬時態(transient):這種物件沒有唯一的標識OID,沒有被Session管理
- 持久態(persistent):這種物件有唯一的標識OID,並且被Session管理
- 脫管態(detached):這種物件有唯一的標識OID,沒有被Session管理
3.4、持久化類的轉換
- 瞬時態物件
- 獲得:直接new物件
- 狀態轉換:
- 瞬時態->持久態:save、saveOrUpdate
- 瞬時態->託管態:直接設定OID
- 持久態物件(特性:可以自動更新資料庫)
- 獲得:get、load、find、iterate
- 狀態轉換
- 持久態->瞬時態:delete
- 持久態->託管態:evict、close、clear
- 託管態物件
- 獲得:直接new物件,然後設定OID
- 狀態轉換:
- 託管態->持久態:update、saveOrUpdate、lock
- 託管態->瞬時態:直接設定OID為null
第四章 Hibernate5對映關係
本章我們要對複雜的對映關係進行學習,按照前邊的學習重新搭建一個專案:hibernate_crm
開啟資料庫,重新建立一個資料庫,資料庫表,下文會一一給出,在此我們先不建立
Hibernate框架實現了ORM的思想,將關聯式資料庫中表的資料對映成物件,使開發人員把對資料庫的操作轉化為對物件的操作,Hibernate的關聯關係對映主要包括多表的對映配置、資料的增加、刪除等。
資料庫中多表之間存在著三種關係,也就是系統設計中的三種實體關係。如圖所示:
溫馨提示:本章節全部學習完最終的效果是這樣的
4.1、一對多關聯
4.1.1、建立資料表
crm_cst_customer(客戶表)
CREATE TABLE `cst_customer` (
`cust_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(主鍵)',
`cust_name` VARCHAR(32) DEFAULT NULL COMMENT '客戶名稱',
`cust_source` VARCHAR(32) DEFAULT NULL COMMENT '客戶資訊來源',
`cust_industry` VARCHAR(32) DEFAULT NULL COMMENT '客戶所屬行業',
`cust_level` VARCHAR(32) DEFAULT NULL COMMENT '客戶級別',
`cust_phone` VARCHAR(64) DEFAULT NULL COMMENT '固定電話',
`cust_mobile` VARCHAR(16) DEFAULT NULL COMMENT '行動電話',
PRIMARY KEY (`cust_id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
crm_cst_linkman(聯絡人表)
CREATE TABLE `cst_linkman` (
`lkm_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '聯絡人編號(主鍵)',
`lkm_name` VARCHAR(16) DEFAULT NULL COMMENT '聯絡人姓名',
`lkm_gender` CHAR(1) DEFAULT NULL COMMENT '聯絡人性別',
`lkm_phone` VARCHAR(16) DEFAULT NULL COMMENT '聯絡人辦公電話',
`lkm_mobile` VARCHAR(16) DEFAULT NULL COMMENT '聯絡人手機',
`lkm_email` VARCHAR(64) DEFAULT NULL COMMENT '聯絡人郵箱',
`lkm_qq` VARCHAR(16) DEFAULT NULL COMMENT '聯絡人qq',
`lkm_position` VARCHAR(16) DEFAULT NULL COMMENT '聯絡人職位',
`lkm_memo` VARCHAR(512) DEFAULT NULL COMMENT '聯絡人備註',
`lkm_cust_id` BIGINT(32) NOT NULL COMMENT '客戶id',
PRIMARY KEY (`lkm_id`),
KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),
CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
4.1.2、編寫實體物件
Customer.java(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/Customer.java)
package com.caochenlei.hibernate.crm;
import java.util.HashSet;
import java.util.Set;
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
// 放置的是多的一方的集合
private Set<LinkMan> linkMans = new HashSet<LinkMan>();
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry(String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level() {
return cust_level;
}
public void setCust_level(String cust_level) {
this.cust_level = cust_level;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
public Set<LinkMan> getLinkMans() {
return linkMans;
}
public void setLinkMans(Set<LinkMan> linkMans) {
this.linkMans = linkMans;
}
}
LinkMan.java(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/LinkMan.java)
package com.caochenlei.hibernate.crm;
public class LinkMan {
private Long lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
// 放置的是一的一方的物件
private Customer customer;
public Long getLkm_id() {
return lkm_id;
}
public void setLkm_id(Long lkm_id) {
this.lkm_id = lkm_id;
}
public String getLkm_name() {
return lkm_name;
}
public void setLkm_name(String lkm_name) {
this.lkm_name = lkm_name;
}
public String getLkm_gender() {
return lkm_gender;
}
public void setLkm_gender(String lkm_gender) {
this.lkm_gender = lkm_gender;
}
public String getLkm_phone() {
return lkm_phone;
}
public void setLkm_phone(String lkm_phone) {
this.lkm_phone = lkm_phone;
}
public String getLkm_mobile() {
return lkm_mobile;
}
public void setLkm_mobile(String lkm_mobile) {
this.lkm_mobile = lkm_mobile;
}
public String getLkm_email() {
return lkm_email;
}
public void setLkm_email(String lkm_email) {
this.lkm_email = lkm_email;
}
public String getLkm_qq() {
return lkm_qq;
}
public void setLkm_qq(String lkm_qq) {
this.lkm_qq = lkm_qq;
}
public String getLkm_position() {
return lkm_position;
}
public void setLkm_position(String lkm_position) {
this.lkm_position = lkm_position;
}
public String getLkm_memo() {
return lkm_memo;
}
public void setLkm_memo(String lkm_memo) {
this.lkm_memo = lkm_memo;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
4.1.3、編寫對映檔案
Customer.hbm.xml(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/Customer.hbm.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.caochenlei.hibernate.crm.Customer" table="cst_customer">
<!-- 設定主鍵欄位對映 -->
<id name="cust_id" column="cust_id">
<generator class="native"/>
</id>
<!-- 設定普通欄位對映 -->
<property name="cust_name" column="cust_name"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
<!-- 配置一對多的對映:放置的是多的一方的集合 -->
<!--
set標籤:
* name :多的一方的物件集合的屬性名稱
* cascade :級聯(儲存更新、刪除)
* inverse :放棄外來鍵維護權(14億人民記住1個主席名稱很容易,但是你讓1個主席記住14億人名稱很難,所以一方放棄)
-->
<set name="linkMans" cascade="save-update,delete" inverse="true">
<!--
key標籤:
* column:多的一方的外來鍵的名稱
-->
<key column="lkm_cust_id"/>
<!--
one-to-many標籤:
* class:多的一方的類的全路徑
-->
<one-to-many class="com.caochenlei.hibernate.crm.LinkMan"/>
</set>
</class>
</hibernate-mapping>
LinkMan.hbm.xml(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/LinkMan.hbm.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.caochenlei.hibernate.crm.LinkMan" table="cst_linkman">
<!-- 設定主鍵欄位對映 -->
<id name="lkm_id" column="lkm_id">
<generator class="native"/>
</id>
<!-- 設定普通欄位對映 -->
<property name="lkm_name" column="lkm_name"/>
<property name="lkm_gender" column="lkm_gender"/>
<property name="lkm_phone" column="lkm_phone"/>
<property name="lkm_mobile" column="lkm_mobile"/>
<property name="lkm_email" column="lkm_email"/>
<property name="lkm_qq" column="lkm_qq"/>
<property name="lkm_position" column="lkm_position"/>
<property name="lkm_memo" column="lkm_memo"/>
<!-- 配置多對一的關係:放置的是一的一方的物件 -->
<!--
many-to-one標籤:
* name :一的一方的物件的屬性名稱
* class :一的一方的類的全路徑
* column :在多的一方的表的外來鍵的名稱
* cascade :級聯(儲存更新、刪除)
-->
<many-to-one name="customer" class="com.caochenlei.hibernate.crm.Customer" column="lkm_cust_id" cascade="save-update,delete"/>
</class>
</hibernate-mapping>
4.1.4、編寫測試檔案
OneToManyTest.java(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/OneToManyTest.java)
package com.caochenlei.hibernate.crm;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.caochenlei.hibernate.utils.HibernateUtil;
public class OneToManyTest {
/**
* 不使用級聯,儲存客戶,儲存聯絡人
* 去掉Customer.hbm.xml對映檔案中的cascade
* 去掉LinkMan.hbm.xml對映檔案中的cascade
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=create
*/
@Test
public void test1() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 建立兩個客戶
Customer customer1 = new Customer();
customer1.setCust_name("張三");
Customer customer2 = new Customer();
customer2.setCust_name("李四");
// 建立三個聯絡人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("鳳姐");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("如花");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("旺財");
customer1.getLinkMans().add(linkMan1);
customer1.getLinkMans().add(linkMan2);
customer2.getLinkMans().add(linkMan3);
linkMan1.setCustomer(customer1);
linkMan2.setCustomer(customer1);
linkMan3.setCustomer(customer2);
session.save(customer1);
session.save(customer2);
session.save(linkMan1);
session.save(linkMan2);
session.save(linkMan3);
tx.commit();
}
/**
* 使用級聯,插入客戶,級聯儲存聯絡人
* 加上Customer.hbm.xml對映檔案中的cascade
* 去掉LinkMan.hbm.xml對映檔案中的cascade
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=create
*/
@Test
public void test2() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 建立兩個客戶
Customer customer1 = new Customer();
customer1.setCust_name("張三");
Customer customer2 = new Customer();
customer2.setCust_name("李四");
// 建立三個聯絡人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("鳳姐");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("如花");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("旺財");
customer1.getLinkMans().add(linkMan1);
customer1.getLinkMans().add(linkMan2);
customer2.getLinkMans().add(linkMan3);
linkMan1.setCustomer(customer1);
linkMan2.setCustomer(customer1);
linkMan3.setCustomer(customer2);
session.save(customer1);
session.save(customer2);
tx.commit();
}
/**
* 使用級聯,插入聯絡人,級聯儲存客戶
* 去掉Customer.hbm.xml對映檔案中的cascade
* 加上LinkMan.hbm.xml對映檔案中的cascade
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=create
*/
@Test
public void test3() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 建立兩個客戶
Customer customer1 = new Customer();
customer1.setCust_name("張三");
Customer customer2 = new Customer();
customer2.setCust_name("李四");
// 建立三個聯絡人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("鳳姐");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("如花");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("旺財");
customer1.getLinkMans().add(linkMan1);
customer1.getLinkMans().add(linkMan2);
customer2.getLinkMans().add(linkMan3);
linkMan1.setCustomer(customer1);
linkMan2.setCustomer(customer1);
linkMan3.setCustomer(customer2);
session.save(linkMan1);
session.save(linkMan2);
session.save(linkMan3);
tx.commit();
}
/**
* 測試物件導航
* 加上Customer.hbm.xml對映檔案中的cascade
* 加上LinkMan.hbm.xml對映檔案中的cascade
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=create
*/
@Test
public void test4() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("李兵");
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("鳳姐");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("如花");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("芙蓉");
linkMan1.setCustomer(customer);
customer.getLinkMans().add(linkMan2);
customer.getLinkMans().add(linkMan3);
//session.save(linkMan1); // 傳送幾條insert語句 4條
//session.save(customer); // 傳送幾條insert語句 3條
//session.save(linkMan2); // 傳送幾條insert語句 1條
tx.commit();
}
/**
* 測試級聯刪除,刪除客戶,級聯刪除聯絡人
* 加上Customer.hbm.xml對映檔案中的cascade
* 去掉LinkMan.hbm.xml對映檔案中的cascade
* 先執行test1進行建表,方便測試,然後執行test5
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=update
*/
@Test
public void test5() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = session.get(Customer.class, 1L);
session.delete(customer);
tx.commit();
}
/**
* 測試級聯刪除,刪除聯絡人,級聯刪除客戶
* 去掉Customer.hbm.xml對映檔案中的cascade
* 加上LinkMan.hbm.xml對映檔案中的cascade
* 先執行test1進行建表,方便測試,然後執行test6
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=update
*/
@Test
public void test6() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
LinkMan linkMan = session.get(LinkMan.class, 1L);
session.delete(linkMan);
tx.commit();
}
/**
* 案例模擬演示,將2號聯絡人原來歸1號客戶,現在改為2號客戶
* 加上Customer.hbm.xml對映檔案中的cascade
* 加上LinkMan.hbm.xml對映檔案中的cascade
* 先執行test1進行建表,方便測試,然後執行test7
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=update
*/
@Test
public void test7() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查詢2號聯絡人
LinkMan linkMan = session.get(LinkMan.class, 2L);
// 查詢2號客戶
Customer customer = session.get(Customer.class, 2L);
// 將2號聯絡人原來歸1號客戶,現在改為2號客戶
linkMan.setCustomer(customer);
customer.getLinkMans().add(linkMan);
session.save(linkMan);
tx.commit();
}
}
4.2、多對多關聯
4.2.1、建立資料表
sys_user(使用者表)
CREATE TABLE `sys_user` (
`user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '使用者id',
`user_code` varchar(32) DEFAULT NULL COMMENT '使用者賬號',
`user_name` varchar(64) DEFAULT NULL COMMENT '使用者名稱稱',
`user_password` varchar(32) DEFAULT NULL COMMENT '使用者密碼',
`user_state` char(1) DEFAULT NULL COMMENT '使用者狀態',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
sys_role(角色表)
CREATE TABLE `sys_role` (
`role_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '角色id',
`role_name` varchar(32) DEFAULT NULL COMMENT '角色名稱',
`role_memo` varchar(128) DEFAULT NULL COMMENT '角色備註',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
sys_user_role(中間表)
CREATE TABLE `sys_user_role` (
`role_id` bigint(32) NOT NULL COMMENT '角色id',
`user_id` bigint(32) NOT NULL COMMENT '使用者id',
PRIMARY KEY (`role_id`,`user_id`),
KEY `FK_user_role_user_id` (`user_id`),
CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.2.2、編寫實體物件
User.java(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/User.java)
package com.caochenlei.hibernate.crm;
import java.util.HashSet;
import java.util.Set;
public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private String user_state;
// 放置的是角色的集合
private Set<Role> roles = new HashSet<Role>();
public Long getUser_id() {
return user_id;
}
public void setUser_id(Long user_id) {
this.user_id = user_id;
}
public String getUser_code() {
return user_code;
}
public void setUser_code(String user_code) {
this.user_code = user_code;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getUser_password() {
return user_password;
}
public void setUser_password(String user_password) {
this.user_password = user_password;
}
public String getUser_state() {
return user_state;
}
public void setUser_state(String user_state) {
this.user_state = user_state;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
Role.java(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/Role.java)
package com.caochenlei.hibernate.crm;
import java.util.HashSet;
import java.util.Set;
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
// 放置的是使用者的集合
private Set<User> users = new HashSet<User>();
public Long getRole_id() {
return role_id;
}
public void setRole_id(Long role_id) {
this.role_id = role_id;
}
public String getRole_name() {
return role_name;
}
public void setRole_name(String role_name) {
this.role_name = role_name;
}
public String getRole_memo() {
return role_memo;
}
public void setRole_memo(String role_memo) {
this.role_memo = role_memo;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
4.2.3、編寫對映檔案
User.hbm.xml(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/User.hbm.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.caochenlei.hibernate.crm.User" table="sys_user">
<!-- 設定主鍵欄位對映 -->
<id name="user_id" column="user_id">
<generator class="native"/>
</id>
<!-- 設定普通欄位對映 -->
<property name="user_code" column="user_code"/>
<property name="user_name" column="user_name"/>
<property name="user_password" column="user_password"/>
<property name="user_state" column="user_state"/>
<!-- 建立與角色的多對多的對映關係 -->
<!--
set標籤:
* name :對方的集合的屬性名稱
* table :多對多的關係需要使用中間表,放的是中間表的名稱
* cascade :級聯(儲存更新、刪除)
-->
<set name="roles" table="sys_user_role" cascade="save-update,delete">
<!--
key標籤:
* column :當前的物件對應中間表的外來鍵的名稱
-->
<key column="user_id"/>
<!--
many-to-many標籤:
* class :對方的類的全路徑
* column :對方的物件在中間表中的外來鍵的名稱
-->
<many-to-many class="com.caochenlei.hibernate.crm.Role" column="role_id"/>
</set>
</class>
</hibernate-mapping>
Role.hbm.xml(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/Role.hbm.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.caochenlei.hibernate.crm.Role" table="sys_role">
<!-- 設定主鍵欄位對映 -->
<id name="role_id" column="role_id">
<generator class="native"/>
</id>
<!-- 設定普通欄位對映 -->
<property name="role_name" column="role_name"/>
<property name="role_memo" column="role_memo"/>
<!-- 建立與使用者的多對多的對映關係 -->
<!--
set標籤:
* name :對方的集合的屬性名稱。
* table :多對多的關係需要使用中間表,放的是中間表的名稱
* cascade :級聯(儲存更新、刪除)
* inverse :放棄外來鍵維護權(被動方放棄)
-->
<set name="users" table="sys_user_role" cascade="save-update,delete" inverse="true">
<!--
key標籤:
* column :當前的物件對應中間表的外來鍵的名稱
-->
<key column="role_id"/>
<!--
many-to-many標籤:
* class :對方的類的全路徑
* column :對方的物件在中間表中的外來鍵的名稱
-->
<many-to-many class="com.caochenlei.hibernate.crm.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>
4.2.4、編寫測試檔案
OneToManyTest.java(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/OneToManyTest.java)
package com.caochenlei.hibernate.crm;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.caochenlei.hibernate.utils.HibernateUtil;
public class ManyToManyTest {
/**
* 不使用級聯,儲存使用者,儲存角色
* 去掉User.hbm.xml對映檔案中的cascade
* 去掉Role.hbm.xml對映檔案中的cascade
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=create
*/
@Test
public void test1() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 建立兩個使用者
User user1 = new User();
user1.setUser_name("趙洪");
User user2 = new User();
user2.setUser_name("李兵");
// 建立三個角色
Role role1 = new Role();
role1.setRole_name("研發部");
Role role2 = new Role();
role2.setRole_name("市場部");
Role role3 = new Role();
role3.setRole_name("公關部");
role1.getUsers().add(user1);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
role3.getUsers().add(user2);
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role2);
user2.getRoles().add(role3);
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
session.save(role3);
tx.commit();
}
/**
* 使用級聯,儲存使用者,級聯儲存角色
* 加上User.hbm.xml對映檔案中的cascade
* 去掉Role.hbm.xml對映檔案中的cascade
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=create
*/
@Test
public void test2() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 建立兩個使用者
User user1 = new User();
user1.setUser_name("趙洪");
User user2 = new User();
user2.setUser_name("李兵");
// 建立三個角色
Role role1 = new Role();
role1.setRole_name("研發部");
Role role2 = new Role();
role2.setRole_name("市場部");
Role role3 = new Role();
role3.setRole_name("公關部");
role1.getUsers().add(user1);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
role3.getUsers().add(user2);
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role2);
user2.getRoles().add(role3);
session.save(user1);
session.save(user2);
tx.commit();
}
/**
* 使用級聯,儲存角色,級聯儲存使用者
* 去掉User.hbm.xml對映檔案中的cascade
* 加上Role.hbm.xml對映檔案中的cascade
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=create
*/
@Test
public void test3() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 建立兩個使用者
User user1 = new User();
user1.setUser_name("趙洪");
User user2 = new User();
user2.setUser_name("李兵");
// 建立三個角色
Role role1 = new Role();
role1.setRole_name("研發部");
Role role2 = new Role();
role2.setRole_name("市場部");
Role role3 = new Role();
role3.setRole_name("公關部");
role1.getUsers().add(user1);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
role3.getUsers().add(user2);
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role2);
user2.getRoles().add(role3);
session.save(role1);
session.save(role2);
session.save(role3);
tx.commit();
}
/**
* 使用級聯,刪除使用者,級聯刪除角色
* 加上User.hbm.xml對映檔案中的cascade
* 去掉Role.hbm.xml對映檔案中的cascade
* 先執行test1進行建表,方便測試,然後執行test4
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=update
*/
@Test
public void test4() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 1L);
session.delete(user);
tx.commit();
}
/**
* 使用級聯,刪除角色,級聯刪除使用者
* 去掉User.hbm.xml對映檔案中的cascade
* 加上Role.hbm.xml對映檔案中的cascade
* 先執行test1進行建表,方便測試,然後執行test5
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=update
*/
@Test
public void test5() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
Role role = session.get(Role.class, 2L);
session.delete(role);
tx.commit();
}
/**
* 案例模擬演示,將2號使用者原有的2號角色改為1號角色
* 加上User.hbm.xml對映檔案中的cascade
* 加上Role.hbm.xml對映檔案中的cascade
* 先執行test1進行建表,方便測試,然後執行test6
* 修改hibernate.cfg.xml中的hibernate.hbm2ddl.auto=update
*/
@Test
public void test6() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查詢2號使用者
User user = session.get(User.class, 2L);
// 查詢1號角色
Role role1 = session.get(Role.class, 1L);
// 查詢2號角色
Role role2 = session.get(Role.class, 2L);
// 將2號使用者原有的2號角色改為1號角色
user.getRoles().remove(role2);
user.getRoles().add(role1);
session.save(user);
tx.commit();
}
}
第五章 Hibernate5查詢方式
修改檔案:hibernate.cfg.xml
修改檔案:Customer.java
新增構造:Customer.java
修改檔案:LinkMan.java
初始資料:InitQueryData.java(全路徑:/hibernate_crm/src/com/caochenlei/hibernate/crm/InitQueryData.java)
package com.caochenlei.hibernate.crm;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.caochenlei.hibernate.utils.HibernateUtil;
public class InitQueryData {
/**
* 執行前:修改hibernate.cfg.xml的hibernate.hbm2ddl.auto=create
* 執行此方法
* 執行後:修改hibernate.cfg.xml的hibernate.hbm2ddl.auto=update
*/
@Test
public void init() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 建立一個客戶
Customer customer1 = new Customer();
customer1.setCust_name("張三");
customer1.setCust_source("電視廣告");
// 建立十個聯絡人
for (int i = 1; i <= 10; i++) {
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("張三的聯絡人" + i);
linkMan.setCustomer(customer1);
customer1.getLinkMans().add(linkMan);
session.save(linkMan);
}
session.save(customer1);
// 建立一個客戶
Customer customer2 = new Customer();
customer2.setCust_name("李四");
customer2.setCust_source("網路論壇");
// 建立十個聯絡人
for (int i = 1; i <= 10; i++) {
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("李四的聯絡人" + i);
linkMan.setCustomer(customer2);
customer2.getLinkMans().add(linkMan);
session.save(linkMan);
}
session.save(customer2);
// 建立一個客戶
Customer customer3 = new Customer();
customer3.setCust_name("王五");
customer3.setCust_source("街邊告示");
// 建立十個聯絡人
for (int i = 1; i <= 10; i++) {
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("王五的聯絡人" + i);
linkMan.setCustomer(customer3);
customer3.getLinkMans().add(linkMan);
session.save(linkMan);
}
session.save(customer3);
// 建立一個客戶
Customer customer4 = new Customer();
customer4.setCust_name("王五");
customer4.setCust_source("電視廣告");
session.save(customer4);
tx.commit();
}
}
5.1、OID查詢
概述:Hibernate根據物件的OID(主鍵)進行檢索
5.1.1、使用get方法
Customer customer = session.get(Customer.class,1L);
5.1.2、使用load方法
Customer customer = session.load(Customer.class,1L);
5.2、物件導航查詢
概述:Hibernate根據一個已經查詢到的物件,獲得其關聯的物件的一種查詢方式
5.2.1、查詢客戶關聯查詢聯絡人
Customer customer = session.get(Customer.class,2L);
Set<LinkMan> linkMans = customer.getLinkMans();
5.2.2、查詢聯絡人關聯查詢客戶
LinkMan linkMan = session.get(LinkMan.class,1L);
Customer customer = linkMan.getCustomer();
5.3、HQL查詢
概述:Hibernate Query Language,Hibernate的查詢語言,是一種物件導向的方式的查詢語言,語法類似SQL。通過session.createQuery(),用於接收一個HQL進行查詢方式。一般來說,它查詢的是物件而不是表,查詢的是物件屬性而不是表欄位
5.3.1、簡單查詢
@Test
public void test1() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查詢所有客戶
Query query = session.createQuery("from Customer");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.3.2、別名查詢
@Test
public void test2() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查詢所有客戶
Query query1 = session.createQuery("from Customer c");
List<Customer> list1 = query1.list();
for (Customer customer : list1) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
// 查詢所有客戶
Query query2 = session.createQuery("select c from Customer c");
List<Customer> list2 = query2.list();
for (Customer customer : list2) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.3.3、排序查詢
@Test
public void test3() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 採用鏈式呼叫,預設情況(升序)
List<Customer> list1 = session.createQuery("from Customer order by cust_id").list();
for (Customer customer : list1) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
// 採用鏈式呼叫,升序情況
List<Customer> list2 = session.createQuery("from Customer order by cust_id asc").list();
for (Customer customer : list2) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
// 採用鏈式呼叫,降序情況
List<Customer> list3 = session.createQuery("from Customer order by cust_id desc").list();
for (Customer customer : list3) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.3.4、條件查詢
@Test
public void test4() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 條件查詢:按引數位置繫結
Query query1 = session.createQuery("from Customer where cust_source = ? and cust_name like ?");
query1.setParameter(0, "電視廣告");
query1.setParameter(1, "王%");
List<Customer> list1 = query1.list();
for (Customer customer : list1) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
// 條件查詢:按引數名稱繫結
Query query2 = session.createQuery("from Customer where cust_source = :aaa and cust_name like :bbb");
query2.setParameter("aaa", "電視廣告");
query2.setParameter("bbb", "王%");
List<Customer> list2 = query2.list();
for (Customer customer : list2) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.3.5、投影查詢
@Test
public void test5() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查詢所有客戶名稱:單個欄位查詢
Query query1 = session.createQuery("select c.cust_name from Customer c");
List<Object> list1 = query1.list();
for (Object cust_name : list1) {
System.out.println(cust_name);
}
System.err.println("--------------------------------------------------");
// 查詢所有客戶名稱、客戶來源:多個欄位查詢,封裝到陣列中
Query query2 = session.createQuery("select c.cust_name,c.cust_source from Customer c");
List<Object[]> list2 = query2.list();
for (Object[] objects : list2) {
System.out.println(Arrays.toString(objects));
}
System.err.println("--------------------------------------------------");
// 查詢所有客戶名稱、客戶來源:多個欄位查詢,封裝到物件中
Query query3 = session.createQuery("select new Customer(c.cust_name,c.cust_source) from Customer c");
List<Customer> list3 = query3.list();
for (Customer customer : list3) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.3.6、分頁查詢
@Test
public void test6() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 分頁查詢
Query query = session.createQuery("from LinkMan");
query.setFirstResult(0);
query.setMaxResults(10);
List<LinkMan> list = query.list();
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.3.7、分組查詢
@Test
public void test7() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 聚合函式:count(),max(),min(),avg(),sum()
Object object = session.createQuery("select count(*) from Customer").uniqueResult();
System.out.println(object);
System.err.println("--------------------------------------------------");
// 分組統計:
List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source").list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.3.8、多表查詢
@Test
public void test8() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 內連線
List<Object[]> list1 = session.createQuery("from Customer c inner join c.linkMans").list();
for (Object[] objects : list1) {
System.out.println(Arrays.toString(objects));
}
System.err.println("--------------------------------------------------");
// 迫切內連線(hibernate獨有,將另一個物件的資料封裝到該物件中)
List<Customer> list2 = session.createQuery("select distinct c from Customer c inner join fetch c.linkMans").list();
for (Customer customer : list2) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
// 左外連線
List<Object[]> list3 = session.createQuery("from Customer c left outer join c.linkMans").list();
for (Object[] objects : list3) {
System.out.println(Arrays.toString(objects));
}
System.err.println("--------------------------------------------------");
// 迫切左外連線(hibernate獨有,將另一個物件的資料封裝到該物件中)
List<Customer> list4 = session.createQuery("select distinct c from Customer c left outer join fetch c.linkMans").list();
for (Customer customer : list4) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
// 右外連線
List<Object[]> list5 = session.createQuery("from Customer c right outer join c.linkMans").list();
for (Object[] objects : list5) {
System.out.println(Arrays.toString(objects));
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.4、QBC查詢
概述:Query By Criteria,條件查詢。是一種更加物件導向化的查詢的方式
5.4.1、簡單查詢
@Test
public void test1() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 查詢所有客戶
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.4.2、排序查詢
@Test
public void test2() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 升序查詢
Criteria criteria1 = session.createCriteria(Customer.class);
criteria1.addOrder(Order.asc("cust_id"));
List<Customer> list1 = criteria1.list();
for (Customer customer : list1) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
// 降序查詢
Criteria criteria2 = session.createCriteria(Customer.class);
criteria2.addOrder(Order.desc("cust_id"));
List<Customer> list2 = criteria2.list();
for (Customer customer : list2) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.4.3、條件查詢
@Test
public void test3() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 條件查詢
Criteria criteria = session.createCriteria(Customer.class);
/**
* 設定條件:
* = eq
* > gt
* >= ge
* < lt
* <= le
* <> ne
* like
* in
* and
* or
*/
criteria.add(Restrictions.eq("cust_source", "電視廣告"));
criteria.add(Restrictions.like("cust_name", "王%"));
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.4.4、分頁查詢
@Test
public void test4() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 分頁查詢
Criteria criteria = session.createCriteria(LinkMan.class);
criteria.setFirstResult(0);
criteria.setMaxResults(10);
List<LinkMan> list = criteria.list();
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
5.4.5、分組查詢
@Test
public void test5() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
/**
* add :分組前的條件
* addOrder :排序
* setProjection :分組後的條件
*/
criteria.setProjection(Projections.rowCount());
Long num = (Long) criteria.uniqueResult();
System.out.println(num);
System.err.println("--------------------------------------------------");
tx.commit();
}
5.4.6、離線查詢
@Test
public void test6() {
// 相當控制層
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
detachedCriteria.add(Restrictions.like("cust_name", "王%"));
// 相當業務層
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
transaction.commit();
}
5.5、SQL查詢
概述:通過使用sql語句進行查詢
@Test
public void test1() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
// 直接查詢
SQLQuery sqlQuery1 = session.createSQLQuery("select * from cst_customer");
List<Object[]> list1 = sqlQuery1.list();
for (Object[] objects : list1) {
System.out.println(Arrays.toString(objects));
}
System.err.println("--------------------------------------------------");
// 物件查詢
SQLQuery sqlQuery2 = session.createSQLQuery("select * from cst_customer");
sqlQuery2.addEntity(Customer.class);
List<Customer> list2 = sqlQuery2.list();
for (Customer customer : list2) {
System.out.println(customer);
}
System.err.println("--------------------------------------------------");
tx.commit();
}
第六章 Hibernate5優化機制
6.1、延遲載入
延遲載入:lazy(又稱為懶載入),執行到該行程式碼的時候,不會傳送語句去進行查詢,在真正使用這個物件的屬性的時候才會傳送SQL語句進行查詢
- 類級別的延遲載入
- 指的是通過load方法查詢某個物件的時候,是否採用延遲載入
- 類級別延遲載入通過
上的lazy進行配置,如果讓lazy失效 - 將lazy設定為false
- 將持久化類使用final修飾
- Hibernate. Initialize(物件)
- 關聯級別的延遲載入
- 指的是在查詢到某個物件的時候,查詢其關聯的物件的時候,是否採用延遲載入
- 通過客戶獲得聯絡人的時候,聯絡人物件是否採用了延遲載入,稱為是關聯級別的延遲
- 抓取策略往往會和關聯級別的延遲載入一起使用,優化語句
6.2、抓取策略
抓取策略:通過一個物件抓取到關聯物件需要傳送SQL語句,SQL語句如何傳送,傳送成什麼樣格式通過策略進行配置
6.2.1、<set>上的fetch和lazy
-
fetch:抓取策略,控制SQL語句格式
- select :預設值,傳送普通的select語句,查詢關聯物件
- join :傳送一條迫切左外連線查詢關聯物件
- subselect :傳送一條子查詢查詢其關聯物件
-
lazy:延遲載入,控制查詢關聯物件的時候是否採用延遲
- true :預設值,查詢關聯物件的時候,採用延遲載入
- false :查詢關聯物件的時候,不採用延遲載入
- extra :極其懶惰
在實際開發中,一般都採用預設值,如果有特殊的需求,可能需要配置join
6.2.2、<many-to-one>上的fetch和lazy
-
fetch :抓取策略,控制SQL語句格式
- select :預設值,傳送普通的select語句,查詢關聯物件
- join :傳送一條迫切左外連線查詢關聯物件
-
lazy :延遲載入,控制查詢關聯物件的時候是否採用延遲
- proxy :預設值,proxy具體的取值,取決於另一端的<class>上的lazy的值
- false :查詢關聯物件,不採用延遲
- no-proxy :(不會使用)
在實際開發中,一般都採用預設值,如果有特殊的需求,可能需要配置join
6.3、批量抓取
批量抓取:關聯物件一起抓取,預設抓取一條,可以通過設定batch-size屬性進行調整
- 一的一方的<class>:batch-size="5"(例如:獲取聯絡人的時候,批量去抓取客戶)
- 一的一方的<set>:batch-size="5"(例如:獲取客戶的時候 ,批量去抓取聯絡人 )