Hibernate基礎知識(三)

Hibernate_day03總結

今日內容

Hibernate的檢索方式

Hibernate的抓取策略

Hibernate批量檢索

事務的併發問題

Hibernate的二級緩存

Hibernate的查詢緩存

1.1 上次課內容回顧:

1.Hibernate一級緩存:

* 緩存:優化手段.

* Hibernate中兩個基本緩存:

* 一級緩存:session的生命週期一致.

* 二級緩存:sessionFactory的生命週期一致.

* 證明一級緩存的存在:

* session的生命週期開始

* 查詢了一下Book.//發送SQL去查詢

* 查詢了一個Book.//不發送SQL.

* session的生命週期結束

 

* 一級緩存的管理:

* clear();

* evict(Object obj);

* flush();

* refresh(Object obj);

 

* 一級緩存的刷出時機:

* ALWAYS:

* AUTO:默認值

* COMMIT:事務提交/session.flush()時候

* MANUAL:手動調用session.flush()刷出緩存

 

* 持久化對象的操作的常用方法:

2.Hibernate爲了管理持久化對象:

* 將持久化對象分成三種狀態:

* 瞬時態:

* 沒有唯一標識OID,且沒有與session關聯.

* 持久態:

* 有唯一的標識OID,且與session關聯.

* 脫管態:

* 有唯一的標識OID,沒有與session關聯.

 

* 瞬時態對象:

* Book book = new Book();

* 瞬時-->持久:

* save()/saveOrUpdate();

* 瞬時-->脫管:

* book.setBid(1);

* 持久態對象:

* get()/load()/find()/lock();

* 持久態-->瞬時:

* delete();

* 持久態-->脫管:

* close()/clear()/evict();

* 脫管態對象:

* Book book = new Book();

* book.setBid(1);

* 脫管-->瞬時:

* book.setBid(null);

* 脫管-->持久:

* update();/saveOrUpdate();

 

3.Hibernate的關聯關係配置:

* 一對多:

* 多對多:

* 一對一:

 

一對多:

* 實體:

private class Customer{

private Set<Order> orders = new HashSet<Order>;

}

 

private class Order{

private Customer customer;

}

* 映射文件:

* 在多的一方Order.hbm.xml

<many-to-one />

 

* 在一的一方Customer.hbm.xml

<set>

<key />

<one-to-many />

</set>

 

* cascade:級聯操作:

* save-update:

* delete

* all

* delete-orphan

* all-delete-orphan

* inverse:放棄外鍵維護權

* 通常在一的一方放棄.

 

多對多:

實體:

private class Student{

private Set<Course> courses = new HashSet<Course>();

}

 

private class Course{

private Set<Student> students = new HashSet<Student>();

}

 

映射文件:

在多對多的雙方需要配置:

<set>

<key />

<many-to-many />

</set>

***** 保存多對多雙方的時候,需要有一方放棄外鍵維護權.

 

1.2 Hibernate的檢索方式:

1.2.1 Hibernate的檢索方式:

檢索方式:查詢的方式:

導航對象圖檢索方式:  根據已經加載的對象導航到其他對象

* Customer customer = (Customer)session.get(Customer.class,1);

* customer.getOrders();// 獲得到客戶的訂單

OID 檢索方式:  按照對象的 OID 來檢索對象

* get()/load();方法進行檢索.

HQL 檢索方式: 使用面向對象的 HQL 查詢語言

* Query query = session.createQuery(HQL);

QBC 檢索方式: 使用 QBC(Query By Criteria) API 來檢索對象. 這種 API 封裝了基於字符串形式的查詢語句, 提供了更加面向對象的查詢接口.

* Criteria criteria = session.createCriteria(Customer.class);

本地 SQL 檢索方式: 使用本地數據庫的 SQL 查詢語句

* SQLQuery query = session.createSQLQuery(SQL);

1.2.2 HQL:

HQL:Hibernate Query Language:

* 特點:

* 面向對象的查詢:

* 支持方法鏈編程:

* 使用:

1.創建Query接口.

 

1.查詢所有記錄:

List<Customer> list = session.createQuery("from Customer").list();

for (Customer customer : list) {

System.out.println(customer);

}

 

2.查詢使用別名:

// 使用別名

// 別名as可以省略

/*  List<Customer> list =

  session.createQuery("from Customer  c").list();

  System.out.println(list);*/

 

 

// 使用別名:帶參數

/*List<Customer> list = session

.createQuery("from Customer as c where c.cname = ?")

.setString(0, "小沈").list();

System.out.println(list);*/

// 不支持 select * from Customer寫法.可以寫成 select 別名 from Customer as 別名;

List<Customer> list = session.createQuery("select c from Customer c").list();

System.out.println(list);

 

3.排序:

List<Customer> list = session.createQuery(

"from Customer c order by c.id desc").list();

for (Customer customer : list) {

System.out.println(customer);

}

 

4.分頁查詢:

Query query = session.createQuery("from Order");

query.setFirstResult(20);

query.setMaxResults(10);

List<Order> list = query.list();

for (Order order : list) {

System.out.println(order);

}

 

5.單個對象查詢:

Customer customer = (Customer) session

.createQuery("from Customer where cname = ?")

.setString(0, "小明").uniqueResult();

System.out.println(customer);

 

6.參數綁定:

// 1.使用?號方式綁定

/*Query query = session.createQuery("from Customer where cname = ?");

query.setString(0, "小沈");

List<Customer> list = query.list();

System.out.println(list);*/

/*Query query = session.createQuery("from Customer where cname = ? and cid =?");

query.setString(0, "小沈");

query.setInteger(1,3);

List<Customer> list = query.list();

System.out.println(list);*/

// 2.使用名稱的方式綁定

Query query = session.createQuery("from Customer where cname=:name and cid=:id");

query.setString("name", "小沈");

query.setInteger("id", 3);

List<Customer> list = query.list();

System.out.println(list);

 

// 3.綁定實體

List<Order> list = session

.createQuery("from Order o where o.customer = ?")

.setEntity(0, customer).list();

for (Order order : list) {

System.out.println(order);

}

 

7.投影操作:

// 查詢客戶的名稱:

/*

 * List<Object> list = session.createQuery(

 * "select c.cname from Customer c").list(); System.out.println(list);

 */

 

/*

 * List<Object[]> list = session.createQuery(

 * "select c.cid,c.cname from Customer c").list(); for (Object[] objects

 * : list) { System.out.println(Arrays.toString(objects)); }

 */

 

List<Customer> list = session.createQuery(

"select new Customer(cname) from Customer").list();

System.out.println(list);

 

8.模糊查詢:

Query query = session.createQuery("from Customer where cname like ?");

query.setParameter(0, "%");

List<Customer> list = query.list();

System.out.println(list);

 

SQL多表查詢:

* 連接:

* 交叉連接:

* select * from A,B;

* 內連接:查詢的是兩個表的交集!

* select * from A inner join B on A.字段 = B.字段;

* 隱式內連接:

* select * from A,B where A.字段 = B.字段;

* 外連接:

* 左外連接:

* select * from A left outer join B on  A.字段 = B.字段;

* 右外連接:

* select * from A right outer join B on A.字段 = B.字段;

 

HQL多表的查詢:

* 連接:

* 交叉連接:

* 內連接:

* 隱式內連接:

* 迫切內連接:

* 左外連接:

* 迫切左外連接:

* 右外連接:

 

* HQL的內連接和迫切內連接區別:

* 內連接查詢 :將數據封裝一個List<Object[]>.

* 迫切內連接 :將數據封裝一個List<Customer>.但是迫切內連接,得到會有重複記錄 ,需要使用distinct排重.

1.2.3 QBC:

1.查詢所有記錄:

List<Customer> list = session.createCriteria(Customer.class).list();

for (Customer customer : list) {

System.out.println(customer);

}

 

2.排序:

List<Customer> list = session.createCriteria(Customer.class)

.addOrder(org.hibernate.criterion.Order.desc("id")).list();

for (Customer customer : list) {

System.out.println(customer);

}

 

3.分頁:

Criteria criteria = session.createCriteria(Order.class);

criteria.setFirstResult(10);

criteria.setMaxResults(10);

List<Order> list = criteria.list();

for (Order order : list) {

System.out.println(order);

}

 

4.獲取單個對象:

Customer customer = (Customer) session.createCriteria(Customer.class)

.add(Restrictions.eq("cname", "小明")).uniqueResult();

System.out.println(customer);

 

5.帶參數的查詢:

/*

 * List<Customer> list = session.createCriteria(Customer.class)

 * .add(Restrictions.eq("cname", "小明")).list();

 * System.out.println(list);

 */

 

List<Customer> list = session.createCriteria(Customer.class)

.add(Restrictions.eq("cname", "小明"))

.add(Restrictions.eq("cid", 2)).list();

System.out.println(list);

 

6.模糊查詢:

Criteria criteria = session.createCriteria(Customer.class);

criteria.add(Restrictions.like("cname", "%"));

List<Customer> list = criteria.list();

System.out.println(list);

 

 

1.2.4 SQL:

1.SQL語句查詢所有記錄:

List<Object[]> list = session.createSQLQuery("select * from customer").list();

for (Object[] objects : list) {

System.out.println(Arrays.toString(objects));

}

 

List<Customer> list = session.createSQLQuery("select * from customer")

.addEntity(Customer.class).list();

for (Customer customer : list) {

System.out.println(customer);

}

 

1.3 Hibernate的抓取策略

1.3.1 區分延遲和立即檢索:

立即檢索:

* 當執行某行代碼的時候,馬上發出SQL語句進行查詢.

* get()

延遲檢索:

* 當執行某行代碼的時候,不會馬上發出SQL語句進行查詢.當真正使用這個對象的時候纔會發送SQL語句.

* load();

 

 

類級別檢索和關聯級別檢索:

* 類級別的檢索:

* class>標籤上配置lazy

* 關聯級別的檢索:

* <set>/<many-to-one>上面的lazy.

 

* 查詢某個對象的時候,是否需要查詢關聯對象?

* 查詢關聯對象的時候是否採用延遲檢索?

 

從一的一方關聯多的一方:

* <set>

* fetch:控制sql語句的類型

* join:發送迫切左外連接的SQL查詢關聯對象.fetch=join那麼lazy被忽略了.

* select:默認值,發送多條SQL查詢關聯對象.

* subselect:發送子查詢查詢關聯對象.(需要使用Query接口測試)

 

* lazy:控制關聯對象的檢索是否採用延遲.

* true:默認值, 查詢關聯對象的時候使用延遲檢索

* false:查詢關聯對象的時候不使用延遲檢索.

* extra:及其懶惰.

 

***** 如果fetchjoin的情況,lazy屬性將會忽略.

 

在多的一方關聯一的一方:

* <many-to-one>

* fetch:控制SQL語句發送格式

* join:發送一個迫切左外連接查詢關聯對象.fetch=join,lay屬性會被忽略.

* select:發送多條SQL檢索關聯對象.

* lazy:關聯對象檢索的時候,是否採用延遲

* false:不延遲

* proxy:使用代理.檢索訂單額時候,是否馬上檢索客戶 由Customer對象的映射文件中<class>lazy屬性來決定.

* no-proxy:不使用代理

 

1.4 Hibernate的事務處理:

事務:

* 事務就是邏輯上的一組操作,要麼全都成功,要麼全都失敗!!!

 

事務特性:

* 原子性:事務一組操作不可分割.

* 一致性:事務的執行前後,數據完整性要保持一致.

* 隔離性:一個事務在執行的過程中不應該受到其他事務的干擾.

* 持久性:一旦事務結束,數據就永久保存數據庫.

 

如果不考慮事務的隔離性引發一些安全性問題:

* 5大類問題:3類讀問題 2類寫問題.

* 讀問題:

* 髒讀:一個事務讀到另一個事務未提交數據.

* 不可重複讀:一個事務讀到另一個事務已經提交數據(update),導致查詢結果不一致.

* 虛讀:一個事務讀到另一個事務已經提交的數據(insert),導致查詢結果不一致

 

* 避免三種讀的問題:

* 設置事務的隔離級別:

* 未提交讀:以上三種讀問題 都有可能發生.

* 已提交讀:避免髒讀,但是不可重複讀和虛讀有可能發生.

* 重複讀:避免髒讀和不可重複讀,但是虛讀是有可能發生.

* 串行的:可以避免以上三種讀問題.

 

* Hibernate中設置事務的隔離級別:

* 在覈心配置文件中:

<property name="hibernate.connection.isolation">4</property>

 

* 寫問題:丟失更新

* 解決;

* 悲觀鎖:

*

* 樂觀鎖;

*

 

線程綁定的session:

* Hibernate.cfg.xml中配置一個:

<property name="hibernate.current_session_context_class">thread</property>

* 使用SessionFactory中的getCurrentSession();方法.

* 底層就是ThreadLocal.

 

***** 當前線程中的session不需要進行關閉,線程結束後自動關閉!!!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章