Hibernate【查詢、鏈接池、逆向工程】

前言

在Hibernate的第二篇中只是簡單地說了Hibernate的幾種查詢方式....到目前爲止,咱們都是使用一些簡單的主鍵查詢阿...使用HQL查詢全部的數據....本博文主要講解Hibernate的查詢操做,鏈接池,逆向工程的知識點...java

get/load主鍵查詢

因爲主鍵查詢這個方法用得比較多,因而Hibernate專門爲咱們封裝了起來...sql

  • 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不支持*號**,下面的代碼是錯誤的。session

//不能用*
    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還提供了將對象數組封裝成對象的功能ide

  • 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的配置文件能夠在\project\etc找到

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

相關文章
相關標籤/搜索