Hibernate【查詢、連線池、逆向工程】

Java3y發表於2019-03-04

前言

在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

相關文章