前言
在Hibernate的第二篇中只是簡單地說了Hibernate的幾種查詢方式….到目前為止,我們都是使用一些簡單的主鍵查詢阿…使用HQL查詢所有的資料….本博文主要講解Hibernate的查詢操作,連線池,逆向工程的知識點…
get/load主鍵查詢
由於主鍵查詢這個方法用得比較多,於是Hibernate專門為我們封裝了起來…
- get()立即查詢
- load()懶載入
物件導航查詢
如果物件與物件之前存在一對多、多對一的關係的時候
- 在以前SQL查詢的時候:我們如果想要得到當前物件與另一物件的關聯關係的時候,就必須用多表查詢來得到資料
- Hibernate提供了物件導航查詢:我們可以使用主鍵查詢完之後,得到的物件,直接使用物件得到集合…就可以得到對應的資料了。
// 物件導航查詢
Dept dept = (Dept) session.get(Dept.class, 12);
System.out.println(dept.getDeptName());
//這裡就可以得到部門對應的所有員工
System.out.println(dept.getEmps());
複製程式碼
HQL查詢
在Hibernate的前面章節中已經講解過了基本的概念了。在這裡我們就直接看看怎麼使用了。
值得注意的是:
- 在hbm.xml檔案中的auto-import=”true” 要設定true。當然了,預設值就是ture
- 如果是false,寫hql的時候,要指定類的全名
查詢全部列
//方式一:直接寫物件
Query q = session.createQuery("from Dept");
//方式二:可以為物件取別名
Query q = session.createQuery("select d from Dept d");
複製程式碼
值得注意的是:HQL不支援*號,下面的程式碼是錯誤的。
//不能用*
Query q = session.createQuery("select * from Dept d");
複製程式碼
查詢指定的列
值得注意的是:使用HQL查詢指定的列,返回的是物件陣列Object[]
//只查詢name和eatBanana列
Query query = session.createQuery("select m.name,m.eatBanana from Monkey m");
System.out.println(query.list());
複製程式碼
封裝物件
前面測試了查詢指定的列的時候,返回的是物件陣列…可是物件陣列我們不好操作啊…Hibernate還提供了將物件陣列封裝成物件的功能
- JavaBean要有對應的建構函式
Query query = session.createQuery("select new Monkey(m.name,m.eatBanana )from Monkey m");
複製程式碼
條件查詢
在SQL中條件查詢我們也用得比較多,我們來看看HQL中的條件查詢有什麼新特性。
佔位符
佔位符就是指?號,我們在SQL中也常常用…
Query query = session.createQuery("from Monkey m where m.name=?");
//HQL是從0開始的
query.setParameter(0, "大猴子");
System.out.println(query.list());
複製程式碼
命名引數
HQL還支援命名引數查詢!下面我們來看一下怎麼用:
語法::命名
Query query = session.createQuery("from Monkey m where m.name=:monkeyName");
//HQL是從0開始的
query.setParameter("monkeyName", "大猴子");
System.out.println(query.list());
複製程式碼
範圍查詢
範圍查詢就是使用between and關鍵字來查詢特定範圍的資料。。和SQL是一樣的…
Query q = session.createQuery("from Dept d where deptId between ? and ?");
q.setParameter(0, 1);
q.setParameter(1, 20);
System.out.println(q.list());
複製程式碼
模糊查詢
模糊查詢就是使用Like關鍵字進行查詢,和SQL也是一樣的。
- %號要寫在引數上,不能寫帶SQL上!
//模糊
Query q = session.createQuery("from Dept d where deptName like ?");
q.setString(0, "%部%");
System.out.println(q.list());
複製程式碼
聚合函式統計
我們也經常會查詢資料庫中一共有多少條記錄這樣的需求。那麼在HQL中怎麼用呢?
- HQL提供了uniqueResult()這麼一個方法,返回只有一條記錄的資料
Query query = session.createQuery("select COUNT(*) from Monkey");
Object o = query.uniqueResult();
System.out.println(o);
複製程式碼
分組查詢
分組查詢和SQL是一樣的…
//-- 統計t_employee表中,每個部門的人數
//資料庫寫法:SELECT dept_id,COUNT(*) FROM t_employee GROUP BY dept_id;
// HQL寫法
Query q = session.createQuery("select e.dept, count(*) from Employee e group by e.dept");
System.out.println(q.list());
複製程式碼
連線查詢
連線查詢也就是多表查詢…多表查詢有三種
- 內連線【等值連線】
- 左外連線
- 有外連結
值得注意的是:連線查詢返回的也是物件陣列!
//1) 內連線 【對映已經配置好了關係,關聯的時候,直接寫物件的屬性即可】
Query q = session.createQuery("from Dept d inner join d.emps");
//2) 左外連線
Query q = session.createQuery("from Dept d left join d.emps");
//3) 右外連線
Query q = session.createQuery("from Employee e right join e.dept");
q.list();
複製程式碼
迫切連線
由於連線查詢返回的是物件陣列,我們使用物件陣列來操作的話會很不方便…既然是連線查詢,那麼物件與物件是肯定有關聯關係的…於是乎,我們想把左表的資料填充到右表中,或者將右表的資料填充到左表中…使在返回的時候是一個物件、而不是物件陣列!HQL提供了fetch關鍵字供我們做迫切連線~
//1) 迫切內連線 【使用fetch, 會把右表的資料,填充到左表物件中!】
Query q = session.createQuery("from Dept d inner join fetch d.emps");
q.list();
//2) 迫切左外連線
Query q = session.createQuery("from Dept d left join fetch d.emps");
q.list();
複製程式碼
查詢語句放在配置檔案中【命名查詢】
我們可以在具體的對映配置檔案中存放一些常用的語句。以Dept為例
<!-- 存放sql語句,如果有<>這樣的字元資料,需要使用CDATA轉義! -->
<query name="getAllDept">
<![CDATA[
from Dept d where deptId < ?
]]>
</query>
複製程式碼
在程式中,我們可以獲取配置檔案配置的語句
Query q = session.getNamedQuery("getAllDept");
q.setParameter(0, 10);
System.out.println(q.list());
複製程式碼
Criteria 查詢
Criteria是一種完全物件導向的查詢…
Criteria使用的是add()來新增條件。條件又使用一個Restrictions類來封裝
Criteria criteria = session.createCriteria(Monkey.class);
criteria.add(Restrictions.eq())
複製程式碼
我們來簡單看一下Restrictions的方法:
都是一些大於、小於、等於之類的….Criteria查詢就使用不了分組、連線查詢了。
SQLQuery本地SQL查詢
有的時候,我們可能表的結構十分複雜,如果使用關聯對映的話,配置檔案是十分臃腫的…因此,我們並不是把全部的資料表都使用對映的方式來建立資料表…
這時,我們就需要用到SQLQuery來維護我們的資料了..
SQLQuery是不能跨資料庫的,因為Hibernate在配置的時候就指定了資料庫的“方言”…
SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM monkey_ limit 0,3");
System.out.println(sqlQuery.list());
複製程式碼
返回的也是物件陣列:
Hibernate也支援在SQLQuery中對資料進行物件封裝..只要新增型別就行了
SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM monkey_ limit 0,3").addEntity(Monkey.class);
System.out.println(sqlQuery.list());
複製程式碼
分頁查詢
傳統的SQL我們在DAO層中往往都是使用兩個步驟來實現分頁查詢
- 得到資料庫表中的總記錄數
- 查詢起始位置到末尾位數的資料
Hibernate對分頁查詢也有很好地支援,我們來一下:
Query query = session.createQuery("from Monkey");
//得到滾動結果集
ScrollableResults scroll = query.scroll();
//滾動到最後一行
scroll.last();
int i = scroll.getRowNumber() + 1;
System.out.println("總計路數:" + i);
//設定分頁位置
query.setFirstResult(0);
query.setMaxResults(3);
System.out.println(query.list());
複製程式碼
- 提供了方法讓我們設定起始位置和結束位置
- 提供了ScrollableResults來得到滾動結果集,最終得到總記錄數
值得注意的是,滾動結果集是從0開始的,因此需要+1才可得到總記錄數!
如果我們們使用的是SELECT COUNT(*) FROM 實體
,我們可以通過uniqueResult()方法獲取資料的唯一記錄,得到的資料轉換成Long型別即可。
Long totalRecord = (Long) queryCount.uniqueResult();
複製程式碼
Hibernate連線池
Hibernate自帶了連線池,但是呢,該連線池比較簡單..而Hibernate又對C3P0這個連線池支援…因此我們來更換Hibernate連線池為C3P0
檢視Hibernate自帶的連線池
我們可以通過Hibernate.properties檔案中檢視Hibernate預設配置的連線池
hibernate.properties的配置檔案可以在projectetc
找到
Hibernate的自帶連線池啥都沒有,就一個連線數量為1…
檢視Hibernate對C3P0的支援
- #hibernate.c3p0.max_size 2 最大連線數
- #hibernate.c3p0.min_size 2 最小連線數
- #hibernate.c3p0.timeout 5000 超時時間
- #hibernate.c3p0.max_statements 100 最大執行的命令的個數
- #hibernate.c3p0.idle_test_period 3000 空閒測試時間
- #hibernate.c3p0.acquire_increment 2 連線不夠用的時候, 每次增加的連線數
- #hibernate.c3p0.validate false
修改Hibernate連線池
我們在hibernate.cfg.xml中配置C3p0,讓C30P0作為Hibernate的資料庫連線池
查詢Hibernate支援的連線池元件有什麼:
既然找到了,那麼我們在hibernate.cfg.xml中配置對應的類就和相關配置就行了
<!-- 【連線池配置】 -->
<!-- 配置連線驅動管理類 -->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!-- 配置連線池引數資訊 -->
<property name="hibernate.c3p0.min_size">2</property>
<property name="hibernate.c3p0.max_size">4</property>
<property name="hibernate.c3p0.timeout">5000</property>
<property name="hibernate.c3p0.max_statements">10</property>
<property name="hibernate.c3p0.idle_test_period">30000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
複製程式碼
執行緒Session使用
我們建立Session的時候,有兩個方法
- openSession()【每次都會建立新的Session】
- getCurrentSession()【獲取當前執行緒的Session,如果沒有則建立】
一般地,我們使用執行緒Session比較多
如果要使用getCurrentSession(),需要在配置檔案中配置:
<!--配置執行緒Session-->
<property name="hibernate.current_session_context_class">thread</property>
複製程式碼
測試資料
@Test
public void testSession() throws Exception {
//openSession: 建立Session, 每次都會建立一個新的session
Session session1 = sf.openSession();
Session session2 = sf.openSession();
System.out.println(session1 == session2);
session1.close();
session2.close();
//getCurrentSession 建立或者獲取session
// 執行緒的方式建立session
// 一定要配置:<property name="hibernate.current_session_context_class">thread</property>
Session session3 = sf.getCurrentSession();// 建立session,繫結到執行緒
Session session4 = sf.getCurrentSession();// 從當前訪問執行緒獲取session
System.out.println(session3 == session4);
// 關閉 【以執行緒方式建立的session,可以不用關閉; 執行緒結束session自動關閉】
//session3.close();
//session4.close(); 報錯,因為同一個session已經關閉了!
}
複製程式碼
為什麼要使用逆向工程
由於我們每次編寫Hibernate的時候都需要寫實體,寫對映檔案。而且Hibernate的對映檔案也容易出錯。而逆向工程可以幫我們自動生成實體和對映檔案,這樣就非常方便了。
使用PowerDesigner
在設計資料庫表時,我們使用PowerDesigner來生成概念模型物理模型…
設計一個人員組織架構:有機構、部門、員工、領導、角色、許可權。
- 一個機構有多個部門
- 一個部門有多個員工
- 領導可以管理多個部門,同時領導他自己也是員工
- 一個員工可以有多個角色
- 一個角色可以分配給多個人
- 人員角色分配後可以設定是否有效,分配時間等
- 一個角色有多個許可權
概念模型:
在PowerDesigner中,箭頭指向的方向永遠是“一”的一方
生成物理模型:
最後生成物理模型是這樣子的:
生成sql語句
我們可以單個生成,一個一個複製
也可以把整個物理模型的sql語句一起生成:
/*==============================================================*/
/* DBMS name: MySQL 5.0 */
/* Created on: 2017/6/5 20:22:52 */
/*==============================================================*/
drop table if exists person_role;
drop table if exists t_company;
drop table if exists t_dept;
drop table if exists t_employee;
drop table if exists t_person;
drop table if exists t_privilege;
drop table if exists t_role;
drop table if exists t_role_privilege;
/*==============================================================*/
/* Table: person_role */
/*==============================================================*/
create table person_role
(
person_id varchar(32) not null,
role_id varchar(32) not null,
state varchar(32),
primary key (person_id, role_id)
);
/*==============================================================*/
/* Table: t_company */
/*==============================================================*/
create table t_company
(
company_id varchar(32) not null,
name varchar(32),
primary key (company_id)
);
/*==============================================================*/
/* Table: t_dept */
/*==============================================================*/
create table t_dept
(
dept_id varchar(32) not null,
company_id varchar(32) not null,
name varchar(32),
primary key (dept_id)
);
/*==============================================================*/
/* Table: t_employee */
/*==============================================================*/
create table t_employee
(
person_id varchar(32) not null,
dept_id varchar(32),
name varchar(32),
employee_id varchar(32),
primary key (person_id)
);
/*==============================================================*/
/* Table: t_person */
/*==============================================================*/
create table t_person
(
person_id varchar(32) not null,
dept_id varchar(32) not null,
name varchar(32),
primary key (person_id)
);
/*==============================================================*/
/* Table: t_privilege */
/*==============================================================*/
create table t_privilege
(
privilege_id varchar(32) not null,
name varchar(32),
primary key (privilege_id)
);
/*==============================================================*/
/* Table: t_role */
/*==============================================================*/
create table t_role
(
role_id varchar(32) not null,
name varchar(32),
primary key (role_id)
);
/*==============================================================*/
/* Table: t_role_privilege */
/*==============================================================*/
create table t_role_privilege
(
role_id varchar(32) not null,
privilege_id varchar(32) not null,
primary key (role_id, privilege_id)
);
alter table person_role add constraint FK_person_role foreign key (person_id)
references t_person (person_id) on delete restrict on update restrict;
alter table person_role add constraint FK_person_role2 foreign key (role_id)
references t_role (role_id) on delete restrict on update restrict;
alter table t_dept add constraint FK_companty_dept foreign key (company_id)
references t_company (company_id) on delete restrict on update restrict;
alter table t_employee add constraint FK_inherit foreign key (person_id)
references t_person (person_id) on delete restrict on update restrict;
alter table t_person add constraint FK_dept_person foreign key (dept_id)
references t_dept (dept_id) on delete restrict on update restrict;
alter table t_role_privilege add constraint FK_belong foreign key (role_id)
references t_role (role_id) on delete restrict on update restrict;
alter table t_role_privilege add constraint FK_own foreign key (privilege_id)
references t_privilege (privilege_id) on delete restrict on update restrict;
複製程式碼
在資料庫生成八張表:
在Idea下使用Hibernate逆向工程
值得注意的是:Intellij idea下生成出來的對映檔案是沒有對應的關聯關係的。也就是說:一對多或多對多的關係,它是不會幫你自動生成的【好像是這樣子的】。。。因此,需要我們自己新增Set【如果需要】
- https://my.oschina.net/wangyuefive/blog/683771
如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y