Hibernate快速筆記2
1.Hibernate的查詢方式
2.Hibernate的抓取策略
Hibernate查詢方式
-
OID檢索:根據ID查詢物件,Get/Load方法
session.get(Customer.class,1L) session.load(Customer.class, 2L)
-
物件導航檢索:根據已查詢物件,獲得其關聯物件,例如使用者和角色
Customer cus = session.get(Customer.class,1L) LinkMan lkm = cus.getLinkMan()
-
HQL檢索
-
簡單查詢
Query query = session.createQuery("from Customer"); //查詢的是類,不是表 List<Customer> list = query.list(); //list 鏈式顯示獲取 for (Customer customer : list) { System.out.println(customer); } //支援別名,不支援select * session.
-
排序查詢:支援Order by 屬性名,預設升序
List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();
-
條件查詢:1.按位置繫結; 2.按型別繫結
//1.按位置繫結 Query query = session.createQuery("from Customer where cust_id = ? and cust_name like ?"); query.setParameter(0, 1L); query.setParameter(1, "c%"); List<Customer> list = query.list(); //2.按名稱繫結 //冒號後必須緊跟名字,名字可以任意取定 Query query2 = session.createQuery("from Customer where cust_id = :id and cust_name like :name"); query2.setParameter("id", 2L); query2.setParameter("name", "c%"); List<Customer> list2 = query2.list();
-
投影查詢:查詢某些列或某些欄位的行
//單個屬性,返回的Object Query query = session.createQuery("select c.cust_name from Customer c"); List<Object> list = query.list(); for (Object object : list) { System.out.println(object); } //多個列,Object陣列 Query query2 = session.createQuery("select c.cust_id, c.cust_name from Customer c"); List<Object[]> list2 = query2.list(); for (Object[] objects : list2) { System.out.println(Arrays.toString(objects)); } //多列,封裝成物件 Query query3 = session.createQuery("select new Customer(c.cust_id, c.cust_name) from Customer c"); List<Customer> list3 = query3.list();
-
分頁查詢
Query query = session.createQuery("from LinkMan"); query.setFirstResult(10); //limit ?,? query.setMaxResults(10);
-
分組統計查詢
//count,max,min,avg等 Query query = session.createQuery("select min(cust_id) from Customer"); Object result = query.uniqueResult(); System.out.println(result); //也可以使用list,輸出第一個元素 //分組-----注意:lkm_cust_id不是LinkMan的屬性,所以選擇不了 Query query2 = session.createQuery("select customer, count(*) from LinkMan group by lkm_cust_id having count(*) > 1"); List<Object[]> list = query2.list(); for (Object[] objects : list) { System.out.println(Arrays.toString(objects)); }
-
-
QBC檢索:query by criteria,適合多條件查詢
-
簡單查詢
//使用criteria Criteria criteria = session.createCriteria(Customer.class); List<Customer> list = criteria.list(); for (Customer customer : list) { System.out.println(customer); } //使用criteria ,預設升序 Criteria criteria = session.createCriteria(Customer.class); criteria.addOrder(Order.desc("cust_id")); //Order為Hibernate物件 List<Customer> list = criteria.list();
-
條件查詢:add,新增普通條件;addOrder,新增順序;setProjection,新增聚合函式等
//條件查詢 Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); //條件預設是與,可以改成or Criteria criteria = session.createCriteria(Customer.class); // eq = ; lt <; gt >; like,and,or,in,between // criteria.add(Restrictions.eq("cust_name", "cus3")); // criteria.add(Restrictions.le("cust_id", 2L)); //or,兩個條件 //criteria.add(Restrictions.or(Restrictions.eq("cust_name", "cus3"), Restrictions.le("cust_id", 2L))); //or多個條件----可以使用between或者in Disjunction disjunction = Restrictions.disjunction(); disjunction.add(Restrictions.eq("cust_name", "cus3")); disjunction.add(Restrictions.eq("cust_name", "cus1")); disjunction.add(Restrictions.eq("cust_name", "cus1")); criteria.add(disjunction); List<Customer> list = criteria.list();
-
分頁查詢
Criteria criteria = session.createCriteria(Customer.class); criteria.setFirstResult(1); criteria.setMaxResults(1); List<Customer> list = criteria.list();
-
分組統計查詢
Criteria criteria = session.createCriteria(Customer.class); criteria.setProjection(Projections.rowCount()); //Projections.max,min,avg等,還有having,group by等 Long num = (Long) criteria.uniqueResult(); System.out.println(num);
-
-
QBC離線檢索: 適用於多表、多條件和分頁的查詢情況,一般在SSH模型中使用的到
離線:DetachedCriteria,脫離session使用;方便在條件查詢時,減輕了JDBC中的引數查詢語句的匹配重複性問題。可以用來在Web層直接操作,不需要在DAO中判斷
//Web層的操作 DetachedCriteria dc = DetachedCriteria.forClass(Customer.class); dc.add(Restrictions.like("cust_name", "cus%")); //到Service繫結session Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); //執行 Criteria criteria = dc.getExecutableCriteria(session); List<Customer> list = criteria.list(); for (Customer customer : list) { System.out.println(customer); }
-
HQL的多表查詢:QBC也可以,支援功能一般
a) SQL的多表查詢方式:連線查詢和子查詢
-
連線查詢:
-
子查詢:多表巢狀查詢,相關子查詢,非相關子查詢
b) HQL的多表查詢:
-
連線查詢
- 交叉連線
- 內連線:顯式、隱式、迫切
- 外連結:左外、右外、迫切左外
-
普通內連線和迫切內連線只有一個關鍵字fetch不同,其傳送的SQL語句和查詢的結果集都是一樣的,fetch是Hibernate的內容,主要用來將返回結果自動封裝成物件;在普通內連線中,會將連線查詢的每一條結果分成兩個物件來封裝(下面示例程式碼中,能看見普通的內連線會查詢兩個表),而迫切內連線會將相同的封裝到一個物件中。
普通查詢: Transaction transaction = session.beginTransaction(); //SQL的內連線:SELECT * from cst_customer inner join cst_linkman on cst_customer.cust_id = cst_linkman.lkm_cust_id; //HQL只需關聯類中對於外來鍵的集合即可 //查詢結果會匹配到對應的集合中,若去重加上distinct即可 Query query = session.createQuery("from Customer c inner join c.linkMans"); List<Object[]> list = query.list(); for (Object[] objects : list) { System.out.println(Arrays.toString(objects)); }
在console中能看見:
Hibernate: select customer0_.cust_id as cust_id1_0_0_, linkmans1_.lkm_id as lkm_id1_1_1_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_mobile as cust_mob7_0_0_, linkmans1_.lkm_name as lkm_name2_1_1_, linkmans1_.lkm_gender as lkm_gend3_1_1_, linkmans1_.lkm_phone as lkm_phon4_1_1_, linkmans1_.lkm_mobile as lkm_mobi5_1_1_, linkmans1_.lkm_email as lkm_emai6_1_1_, linkmans1_.lkm_qq as lkm_qq7_1_1_, linkmans1_.lkm_position as lkm_posi8_1_1_, linkmans1_.lkm_memo as lkm_memo9_1_1_, linkmans1_.lkm_cust_id as lkm_cus10_1_1_ from cst_customer customer0_ inner join cst_linkman linkmans1_ on customer0_.cust_id=linkmans1_.lkm_cust_id [Customer [cust_id=1, ...] [Customer [cust_id=1, ..., linkMans=[LinkMan [...l] ... //30 行
-
若使用迫切的內連線查詢,則會返回直接封裝好的結果
//迫切內連線 Query query = session.createQuery("from Customer c inner join fetch c.linkMans"); List<Customer> list = query.list(); //能直接獲取到Customer的物件 for (Customer customer : list) { System.out.println(customer); }
我們在console能看到的資訊(若想要看到屬性集合,在tostring函式中新增,否則不會出現linkman)
Hibernate: select customer0_.cust_id as cust_id1_0_0_, linkmans1_.lkm_id as lkm_id1_1_1_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_mobile as cust_mob7_0_0_, linkmans1_.lkm_name as lkm_name2_1_1_, linkmans1_.lkm_gender as lkm_gend3_1_1_, linkmans1_.lkm_phone as lkm_phon4_1_1_, linkmans1_.lkm_mobile as lkm_mobi5_1_1_, linkmans1_.lkm_email as lkm_emai6_1_1_, linkmans1_.lkm_qq as lkm_qq7_1_1_, linkmans1_.lkm_position as lkm_posi8_1_1_, linkmans1_.lkm_memo as lkm_memo9_1_1_, linkmans1_.lkm_cust_id as lkm_cus10_1_1_, linkmans1_.lkm_cust_id as lkm_cus10_1_0__, linkmans1_.lkm_id as lkm_id1_1_0__ from cst_customer customer0_ inner join cst_linkman linkmans1_ on customer0_.cust_id=linkmans1_.lkm_cust_id Customer [cust_id=1, ..., linkMans=[LinkMan [...]] Customer [cust_id=1, ..., linkMans=[LinkMan [...]] ... //30行全部的查詢結果 //使用distinct的結果,只有三行
-
-
SQL查詢
//SQL查詢 SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer"); List<Object[]> list = sqlQuery.list(); // for (Object[] objects : list) { // System.out.println(Arrays.toString(objects)); // } //繫結到類---封裝 sqlQuery.addEntity(Customer.class); List<Customer> list2 = sqlQuery.list(); for (Customer customer : list2) { System.out.println(customer); }
Hibernate抓取策略
Hibernate提供了一系列的優化方式,來提高封裝性帶來的效能問題,尤其在獲取關聯物件的時候。例如一級二級快取(二級一般被Redis替代)機制、和抓取策略等,都是一些用來優化的手段。抓取策略主要是對查詢時的語句等做的優化處理。
優化的方式:1)快取怎麼處理;2)查詢的優化(抓取)
-
延遲載入:懶載入,執行語句的時候,不直接查詢;當使用到關聯的物件才傳送查詢語句。
-
類級別的延遲載入:如load方法,可以在xml的class配置檔案中的
lazy = ‘true’(預設)
,若配置為false
則load方法也是直接載入,不使用延遲載入。<class name="com.leehao.hibernateLearning2.domain.Customer" table="cst_customer" lazy="true">
-
類級別延遲載入通過<class>上的lazy進行配置,如果讓lazy失效
-
將lazy設定為false
-
將持久化類使用final修飾
-
Hibernate. Initialize()
-
-
-
關聯級別的延遲載入:查詢某個物件,獲取物件的關聯物件時。抓取策略往往會和關聯級別的延遲載入一起使用,優化語句。
-
-
抓取策略:通過類載入其關聯物件時,需要傳送SQL語句,如何傳送、什麼時候傳送,與設定的抓取策略有關。可以通過在<set>和<many-to-one>標籤上的fetch屬性來設定。fetch 屬性和lazy屬性一起使用。
<Set>上的fetch和lazy抓取
-
Fetch控制抓取策略,控制的是傳送的SQL語句的格式
- select:預設,傳送普通的select語句,來查詢關聯物件;如根據Customer來查詢聯絡人,會發送多次SQL,每一個物件會查一次————可以使用批量查詢的設定解決
- join:傳送一條迫切的左外連線查詢關聯的物件,只發送一次查詢SQL,這時lazy的控制沒有作用
- subselect:傳送一條子查詢來查詢關聯的物件,和select唯一的不同就是使用子查詢;也是兩次SQL,第二次將所有關聯的東西放入一個表。“相當於”使用了一次select和一次join。
-
lazy:延遲載入,控制查詢關聯物件的時候是否使用延遲
- true:預設,使用延遲載入查詢關聯物件
- false:不使用延遲載入
- extra:“極其懶惰?”
-
在實際開發中,一般都採用預設值。如果有特殊的需求,可能需要配置join
//關聯物件的抓取策略----set中,也就是1的一方,如何查詢它關聯的多的一方的集合 //預設set中,<set name="linkMans" fetch="select" lazy="true"> Customer customer = session.get(Customer.class, 1L); //獲取的時候才會傳送SQL for (LinkMan linkMan : customer.getLinkMans()) { System.err.println(linkMan.getLkm_name()); } ------------------------------------------------------------- //lazy的false或者extra //<set name="linkMans" fetch="select" lazy="extra"> Customer customer = session.get(Customer.class, 1L); //獲取的時候才會傳送SQL System.out.println(customer.getLinkMans().size()); ------------------------------------------------------------- /**注:使用extra時,傳送的SQL語句如下 Hibernate: select count(lkm_id) from cst_linkman where lkm_cust_id =?*/
<many-to-one>上的fetch和lazy抓取
-
fetch
- select:預設
- join:迫切的左外連線,此時lazy失效
-
lazy
- proxy:預設,proxy具體的取值,取決於另一端的<class>上的lazy的值
- false
- no-proxy:不使用
-
在實際開發中,一般都採用預設值。如果有特殊的需求,可能需要配置join
//<many-to-one name="customer" fetch="select" lazy="proxy" class=... Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); LinkMan linkMan = session.get(LinkMan.class, 1L); System.out.println(linkMan.getLkm_name()); System.out.println(linkMan.getCustomer().getCust_name());
批量抓取
獲取多個使用者的多個聯絡人的資訊,可以想象成抓取兩個表的內連線的結果。
1的一方中,在Set中配置batch-size=“n”即可,表示每次抓取n個,預設是1;反之,如果使用如LinkMan批量查詢Customer,則需要在Customer中的class配置。
//<set name="linkMans" batch-size="3">
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
List<Customer> list = session.createQuery("from Customer").list();
for (Customer customer : list) {
System.out.println(customer.getCust_name());
for (LinkMan linkMan: customer.getLinkMans()) {
System.out.println(linkMan.getLkm_name());
}
}
---------------------------------------------------------
Hibernate:
select
customer0_.cust_id as cust_id1_0_,
customer0_.cust_name as cust_nam2_0_,
customer0_.cust_source as cust_sou3_0_,
customer0_.cust_industry as cust_ind4_0_,
customer0_.cust_level as cust_lev5_0_,
customer0_.cust_phone as cust_pho6_0_,
customer0_.cust_mobile as cust_mob7_0_
from
cst_customer customer0_
cus1
Hibernate:
select
linkmans0_.lkm_cust_id as lkm_cus10_1_1_,
linkmans0_.lkm_id as lkm_id1_1_1_,
linkmans0_.lkm_id as lkm_id1_1_0_,
linkmans0_.lkm_name as lkm_name2_1_0_,
linkmans0_.lkm_gender as lkm_gend3_1_0_,
linkmans0_.lkm_phone as lkm_phon4_1_0_,
linkmans0_.lkm_mobile as lkm_mobi5_1_0_,
linkmans0_.lkm_email as lkm_emai6_1_0_,
linkmans0_.lkm_qq as lkm_qq7_1_0_,
linkmans0_.lkm_position as lkm_posi8_1_0_,
linkmans0_.lkm_memo as lkm_memo9_1_0_,
linkmans0_.lkm_cust_id as lkm_cus10_1_0_
from
cst_linkman linkmans0_
where
linkmans0_.lkm_cust_id in (
?, ?, ?
)