Hibernate_day03總結
今日內容
l Hibernate的檢索方式
l Hibernate的抓取策略
l Hibernate的批量檢索
l 事務的併發問題
l Hibernate的二級緩存
l 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:及其懶惰.
***** 如果fetch是join的情況,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不需要進行關閉,線程結束後自動關閉!!!