Hibernate框架入門


Hibernate框架

一、什么是hibernate?

            Hibernate是一個開放源代碼的對象關系映射框架,它對JDBC進行了非常輕量級的對象封裝,它將POJO與數據庫表建立映射關系,是一個全自動的orm框架,hibernate可以自動生成SQL語句,自動執行,使得Java程序員可以隨心所欲的使用對象編程思維來操縱數據庫。 Hibernate可以應用在任何使用JDBC的場合,既可以在Java的客戶端程序使用,也可以在Servlet/JSP的Web應用中使用,最具革命意義的是,Hibernate可以在應用EJB的J2EE架構中取代CMP,完成數據持久化的重任。                                                    

-----------360百科

  確切的說,hibernate其實就是個ORM(Object Relational Mapping)框架,程序員通過操作對象的方式來操作數據庫表的記錄。

二、快速入門

  1.從hibernate官網下載hibernate所需要的jar包

  2.搭建環境

      1) 將下載好的 jar包中lib\required的所有jar包導入web工程下的lib文件夾,這些是部署框架的核心jar包

   2) 導入用於連接數據庫的驅動jar包

   3) 導入日志jar包(如log4j)

    
      

 

 

     

   3.編寫相對應的持久化類,並生成相對應的set/get,toString方法

/**
 * javaBean+屬於他的映射文件=持久化類
 * @author Administrator
 *
 */
public class Customer {
    //注意:這里的數據類型使用包裝類,默認值為null
    private Long cust_id;
    private String cust_name;
    private Long cust_user_id;
    private Long cust_create_id;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_linkman;
    private String cust_phone;
    private String cust_mobile;

    //省略set/get方法

}

 

    4.JavaBean所在的包下創建映射的配置文件(默認放在javabean同包下)

       1)* 默認的命名規則為:實體類名.hbm.xml

       2)* 在xml配置文件中引入約束(引入的是hibernate3.0的dtd約束,不要引入4的約束)

      位置:(hibernate-core-5.0.7.Final.jar\hibernate-core-5.0.7.Final.jar\org.hibernate\hibernate-configuration-3.0.dtd)    

 <!DOCTYPE hibernate-mapping PUBLIC 
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

       3) *寫相對應的映射,此是與數據庫進行映射

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!-- 配置類和表結構的映射 -->
    <class name="com.heima.domain.Customer" table="cst_customer">
        <!-- 配置主鍵 
             見到name屬性,JavaBean的屬性
             見到column屬性,是表結構的字段
        -->
        <id name="cust_id" column="cust_id">
            <!-- 主鍵生成策略 --> 
            <generator class="native"/>
        </id>
        <!-- 配置其他的屬性 -->
        <property name="cust_name" column="cust_name"/>
        <property name="cust_user_id" column="cust_user_id"/>
        <property name="cust_create_id" column="cust_create_id"/>
        <property name="cust_source" column="cust_source"/>
        <property name="cust_industry" column="cust_industry"/>
        <property name="cust_level" column="cust_level"/>
        <property name="cust_linkman" column="cust_linkman"/>
        <property name="cust_phone" column="cust_phone"/>
        <property name="cust_mobile" column="cust_mobile"/>
    </class>
</hibernate-mapping>

    5.編寫Hibernate核心的配置文件

       1) 在src目錄下,創建名稱為hibernate.cfg.xml的配置文件

       2)XML中引入DTD約束,位置:(在hibernate-core-5.0.7.Final.jar\hibernate-core-5.0.7.Final.jar\org.hibernate\hibernate-configuration-3.0.dtd<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <!-- 記住:先配置sessionFactory標簽,一個數據庫對應一個sessionFactory標簽-->
    <session-factory>
        <!-- 必須配置的參數,4大參數,數據庫的方言 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://192.168.174.130:3306/hibernate_day01</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
        <!-- 數據庫的方言 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- 可選配置 -->
        <!--顯示SQL語句,在控制台顯示  -->
        <property name="hibernate.show_sql">true</property>
        <!--格式化SQL語句,是的顯示語句更美觀  -->
        <property name="hibernate.format_sql">true</property>
        <!-- 開啟綁定本地的session -->
        <property name="hibernate.current_session_context_class">thread</property>
        <!-- 生成數據庫的表結構
        慎用create:會先刪除原有的表結構,然后再生成一個新的
           update:有則再原有基礎上增加數據,沒有則先創建再添加數據
        -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!-- 映射配置文件 ,需要映入映射的配置文件-->
        <mapping resource="com/heima/domain/Customer.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
 

     6.編寫測試

/**
 * 測試Hibernate框架
 * @author Administrator
 *
 */
public class Demo1 {
    /**
     * 測試保存用戶
     */
    @Test
    public void testSave1(){
        /**
         * 1.先加載配置文件
         * 2.創建sessionFactory對象,生成Session對象(會話)
         * 3.開啟事務
         * 5.編寫保存的代碼
         * 6.提交事務
         * 7.釋放資源
         */
        //1.先加載配置文件
        Configuration config=new Configuration();
        //默認加載src目錄下hibenate.cfg.xml的配置文件
        config.configure();
        //創建sessionFactory對象
        SessionFactory factory=config.buildSessionFactory();
        //創建session對象
        Session session=factory.openSession();
        //開啟事務
        Transaction tr=session.beginTransaction();
        //編寫保存的代碼
        Customer c=new Customer();
        //c.setCust_id(cust_id);  主鍵是自動遞增,不需要自己設置
        c.setCust_name("測試3");
        c.setCust_level("2");
        c.setCust_phone("110");
        //保存數據,操作對象就相當於操作數據庫的表結構
        session.save(c);
        //提交事務
        tr.commit();
        //釋放資源
        session.close();
        factory.close();
        
   }
}

   其中:

     1. Configuration類

      * Configuration對象用於配置並且啟動Hibernate。

      * Hibernate應用通過該對象來獲得對象-關系映射文件中的元數據,以及動態配置Hibernate的屬性,然后創建SessionFactory對象。

   2.SessionFactory

    *它是工廠類,是生成Session對象的工廠類

   *SessionFactory對象中保存了當前的數據庫配置信息和所有映射關系以及預定義的SQL語句。同時,SessionFactory還負責維護Hibernate的二級緩存。

三、代碼優化

    1.基於每次進行數據處理時都需要調用session,可以將它抽取出來,作為一個公共類

    

       綁定本地的Session

      1.現在的Hibernate框架中,使用session對象開啟事務,所以需要來傳遞session對象,框架提供了ThreadLocal的方式

      * 需要在hibernate.cfg.xml的配置文件中提供配置

          

* <property name="hibernate.current_session_context_class">thread</property>   <!--(注意:放在mapping標簽之前)-->

 

       * 使用SessionFactory的getCurrentSession()方法,獲取當前的Session對象。並且該Session對象不用手動關閉,線程結束了,會自動關閉

  public static Session getCurrentSession(){

            return factory.getCurrentSession();

        }

 

 

    * 注意:想使用getCurrentSession()方法,必須要先配置才能使用。

package com.itheima.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * Hibernate框架的工具類
 * @author Mr_佳先森
 *
 */
public class HibernateUtils {
    //ctrl+shift+x將小寫字母變成大寫,用於常量
    private static final Configuration CONFIG;
    private static final SessionFactory FACTORY;
    static{
        CONFIG=new Configuration().configure();
        FACTORY=CONFIG.buildSessionFactory();
    }
    /**
     * 從構造工廠中獲取sesson對象
     * openSession:作為一級緩存,可以提升查詢數據效率,但是當session生命周期
     * 結束,程序不可從緩存中獲取數據
     */
    public static Session getSession(){
        return FACTORY.openSession();
    }
    /**
     * getCurrentSession():將session封裝ThreadLocal中,每個線程調用線程不受
     * 其他線程的影響,即達到線程安全,又避免了悲觀鎖的效率低下的問題(即使用樂觀鎖)
     * 需要在核心配置文件中添加
     * @return
     */
    public static Session getCurrentSession(){
        return FACTORY.getCurrentSession();
    }
    public static void main(String[] args) {
        getSession();
    }
}

  

   其中session接口

    1.Session是在Hibernate中使用最頻繁的接口。也被稱之為持久化管理器。它提供了和持久化有關的操作,比如添加、修改、刪除、加載和查詢實體對象

     2.Session是線程不安全的

    3.Session有一個緩存,被稱之為Hibernate的一級緩存。每個Session實例都有自己的緩存

    4.session常用的方法:   

save()     delete()  get()  update()  save()  createQuery()

  

  2.調用工具類

    

/**
 * 測試Hibernate框架
 * @author Administrator
 *
 */
public class Demo1 {
    /**
     * 測試工具類
     */
    @Test
    public void testSave2(){
        Session session=HibernateUtils.getSession();
        //開啟事務
        Transaction tr=session.beginTransaction();
        //編寫保存的代碼
        Customer c=new Customer();
        //c.setCust_id(cust_id);  主鍵是自動遞增,不需要自己設置
        c.setCust_name("美美");
        c.setCust_level("2");
        c.setCust_phone("120");
        //保存數據,操作對象就相當於操作數據庫的表結構
        session.save(c);
        //提交事務
        tr.commit();
        //釋放資源
        session.close();
    }
    /**
     * 測試查詢方法,通過主鍵來查詢一條記錄
     */
    @Test
    public void testGet(){
        Session session=HibernateUtils.getSession();
        //這里因為是查詢事務,所以無需要是事務
        //Transaction tr=session.beginTransaction();
        //這里因為主鍵是Long類型,所以數字后面要加個L
        Customer coustomer=session.get(Customer.class, 2L);
        System.out.println(coustomer);
        //tr.commit();
        session.close();
    }
    /**
     * 測試刪除的方法
     * 注意:刪除或者修改之前,要先查詢在刪除或者修改
     */
    @Test
    public void testDel(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        Customer c=session.get(Customer.class,2L);
        session.delete(c);
        tr.commit();
        session.close();
    }
    /**
     * 測試修改的方法
     */
    @Test
    public void testUpdate(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        Customer c=session.get(Customer.class,3L);
        c.setCust_name("小蒼");
        c.setCust_level("3");
        session.update(c);
        tr.commit();
        session.close();
    }
    /**
     *添加或者修改
     */
    @Test
    public void testSaveOrUpdate(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        //Customer c=new Customer();
        //注意:這里的id值不能自己設置,否則會報錯,因為他是由框架管理
        //c.setCust_id(4L);
        //注意:查詢的id必須存在,否則會報空指針異常
        Customer c=session.get(Customer.class,3L);
        c.setCust_name("小菜");
        session.saveOrUpdate(c);
        tr.commit();
        session.close();
    }
    /**
     * 測試一個查詢的方法
     */
    @Test
    public void testSel(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        //創建一個查詢的接口
        Query query=session.createQuery("from Customer");
        //查詢所有的數據select * from 表名
        List<Customer> list=query.list();
        for(Customer c:list){
            System.out.println(c);
        }
        tr.commit();
        session.close();
        
    }
    /**
     * 測試Hibernate框架正規寫法
     */
    @Test
    public void testSave3(){
        Session session=null;
        Transaction tr=null;
        try{
            session=HibernateUtils.getSession();
            tr=session.beginTransaction();
            Customer c=new Customer();
            c.setCust_name("小強");
            session.save(c);
            tr.commit();
        }catch(Exception e){
            tr.rollback();
            e.printStackTrace();
        }finally{
            session.close();
        }
    }
}

四、Hibernate的緩存   

     1.Hibernate框架提供了兩種緩存

         * 一級緩存  -- 自帶的不可卸載的.一級緩存的生命周期與session一致.一級緩存稱為session級別的緩存.

              * 二級緩存  -- 默認沒有開啟,需要手動配置才可以使用的.二級緩存可以在多個session中共享數據,二級緩存稱為是sessionFactory級別的緩存.

       2.Session對象的緩存概述

          * Session接口中,有一系列的java的集合,這些java集合構成了Session級別的緩存(一級緩存).將對象存入到一級緩存中,session沒有結束生命周期,那么對象在session中存放                   着

       * 內存中包含Session實例 --> Session的緩存(一些集合) --> 集合中包含的是緩存對象!

    3.測試一級緩存存在

       

/**
     * 證明一級緩存存在
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        User user=new User();
        user.setName("小明");
        user.setAge(20);
        //保存用戶
        Serializable id=session.save(user);
        System.out.println(id);
        //獲取對象,不會看到Sql語句
        User user2=session.get(User.class,id);
        System.out.println(user2.getName());
        
        tr.commit();
        session.close();
    }

    

 

五、Hibernate之事務

     1.什么是事務

      事務就是邏輯上的一組操作,組成事務的各個執行單元,操作要么全都成功,要么全都失敗.

    2. 事務的特性

        * 原子性   -- 事務不可分割.

        * 一致性   -- 事務執行的前后數據的完整性保持一致.

        * 隔離性   -- 一個事務執行的過程中,不應該受到其他的事務的干擾.

        * 持久性   -- 事務一旦提交,數據就永久保持到數據庫中.

    3.關於解決數據丟失更新問題

       數據當涉及到並發訪問時,第一想到的是添加鎖機制,java中Thread 有添加synchronized關鍵字,數據庫中也有添加鎖的機制

     1)悲觀鎖

      即在數據庫語句中添加"for update"字句。A事務在操作該條記錄時,會把該條記錄鎖起來,其他事務是不能操作這條記錄的,只有當A事務提交后,鎖釋放了,其他                        事務才能操作該條記錄

     2)樂觀鎖

      在表結構中添加version字段(屬性),默認值為0。A事務在操作完該條記錄,提交事務時,會先檢查版本號,如果發生版本號的值相同時,才可以提交事務。同時                        會更新版本號version=1;B事務操作完該條記錄時,提交事務時,會先檢查版本號,如果發現版本不同時,程序會出現錯誤。

     3)鎖使用方法

       悲觀鎖:   

session.get(Customer.class, 1,LockMode.UPGRADE);

      樂觀鎖:

      1)) 持久化類

public class User {
    private Integer id;
    private String name;
    private Integer age;
    //在javabean中添加屬性(樂觀鎖)
    private Integer version;
    
        //省略set/get toString()方法
    
}
    

       2)) 持久化類映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="com.itheima.domain.User" table="t_user">
            <id name="id" column="id">
            <!-- increment:獲取主鍵的最大值,進行+1,作為主鍵
                          缺點:不適合並發訪問
            -->
                <generator class="increment"></generator>
            </id>
            <!-- 樂觀鎖 ,就添加樂觀鎖的機制-->
            <version name="version"/>
            <property name="name" column="name" length="30"/>
            <property name="age" column="age"/>
        </class>
    </hibernate-mapping>

      3)) 此時可以寫兩個測試查詢的方法,進行debug調試

      關於version,當左邊更改數據時,發現自己的版本(0)與數據庫的版本(1)不一致,說明自己不是最新的版本,會放棄此次操作 

六、hibernate的幾種查詢方式(簡述)

      

/**
 * 測試查詢
 * @author Administrator
 *
 */
public class Demo4 {
    /**
     * 測試Query的查詢接口
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查詢方式
        Query query=session.createQuery("from User");
        List<User> list=query.list();
        for(User user:list){
            System.out.println(user);
        }
        tr.commit();
        session.close();
    }
    /**
     * 添加查詢條件
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查詢方式HQL(是Hibernate的獨有的,操作的是對象)
        Query query=session.createQuery("from User where age>?");
        //寫法二:Query query=session.createQuery("from User where age> :aa");
        //設置值:注意:這里區別於JDBC(下標為1)
        query.setInteger(0,15);
        //query.setInteger("aa",15);
        List<User> list=query.list();
        for(User user:list){
            System.out.println(user);
        }
        tr.commit();
        session.close();
    }
    @Test
    public void run3(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查詢方式HQL(是Hibernate的獨有的,操作的是對象)
        Query query=session.createQuery("from User where name like ?");
        query.setString(0,"%k%");
        List<User> list=query.list();
        for(User user:list){
            System.out.println(user);
        }
        tr.commit();
        session.close();
    }
    /**
     * Criteria接口:條件查詢,非常適合
     * 完全面對對象,沒有太多sql語句
     */
    @Test
    public void run4(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //先獲取到Criteria接口
        Criteria criteria=session.createCriteria(User.class);
        //沒有條件,查詢所有的數據
        List<User> list=criteria.list();
        System.out.println(list);
        tr.commit();
        session.close();
    }
    /**
     * 按條件查詢
     */
    @Test
    public void run5(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //先獲取到Criteria接口
        Criteria criteria=session.createCriteria(User.class);
        //添加查詢條件
        //Criterion是Hibnernate提供的條件查詢的對象,向傳入條件使用的工具類
        //Restrictions提供的靜態方法,拼接查詢條件
        criteria.add(Restrictions.gt("age",18));//gt為大於
        //繼續添加條件
        criteria.add(Restrictions.like("name","%s%"));
        //沒有條件,查詢所有的數據a
        List<User> list=criteria.list();
        System.out.println(list);
        tr.commit();
        session.close();
    }
    
}    

七、hibernate之級聯處理數據

     需求:假設一個客戶對應多個聯系人,每個客戶信息的處理都會牽扯到相對應的聯系人;相反,每一個聯系人的處理也會牽扯到相對應的客戶

    1.創建持久化類

     1)在客戶中添加set集合關聯聯系人

// 一個客戶對應多個聯系人:放的是聯系人的集合.(Hibernate默認使用的集合是Set集合.集合必須要自己手動初始化)
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();

     2)在聯系人中添加客戶屬性用於關聯客戶

 // 聯系人關聯的客戶對象://這里不要寫客戶的外鍵,要編寫一個對象,而這個對象千萬不能自己new,框架會幫你new
    private Customer customer;// ORM框架 Object 

    2.創建相對應的映射文件

     1)在客戶映射文件中配置關聯聯系人的標簽set

<!-- 配置關聯對象 -->
        <!-- 
            set標簽:
                * name屬性:多的一方的集合的屬性名稱.
         -->
        <set name="linkMans">
            <!-- 
                key標簽 :
                    * column屬性:多的一方的外鍵的名稱.
            -->
            <key column="lkm_cust_id"></key>
            <!-- 
                one-to-many標簽:
                    * class屬性:多的一方的類全路徑
             -->
             <one-to-many class="com.clj.domain.LinkMan"/>
        </set>

     2) 在聯系人映射文件中添加<many-to-one>標簽關聯客戶

<!-- 配置關聯對象: -->
        <!-- 
            many-to-one:標簽.代表多對一.
                * name        :一的一方的對象的名稱.
                * class        :一的一方的類的全路徑.
                * column    :表中的外鍵的名稱.
         -->
        <many-to-one name="customer" class="com.clj.domain.Customer" column="lkm_cust_id"/>

   3.編寫測試類

@Test
    // 向客戶 和 聯系人中同時保存數據:
    public void demo1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        // 創建一個客戶
        Customer customer = new Customer();
        customer.setCust_name("張總");
        
        // 創建兩個聯系人:
        LinkMan linkMan1 = new LinkMan();
        linkMan1.setLkm_name("秦助理");
        
        LinkMan linkMan2 = new LinkMan();
        linkMan2.setLkm_name("胡助理");
        
        // 建立關系:
        customer.getLinkMans().add(linkMan1);
        customer.getLinkMans().add(linkMan2);
        
        linkMan1.setCustomer(customer);
        linkMan2.setCustomer(customer);
        
        session.save(customer);
        session.save(linkMan1);
        session.save(linkMan2);
        
        tx.commit();
    }

八、級聯保存

    1.保存一個客戶的同時保存相對應的聯系人

     1)在客戶映射文件中的<set>標簽中添加cascade=save-update屬性

<set name="linkmans" cascade="save-update">
            <!-- 需要出現子標簽 -->
            <key column="lkm_cust_id"/>
            <one-to-many class="com.clj.domain.Linkman"/>
        </set>

 

     2)添加測試類

級聯是有方向性:
* 保存客戶的時候級聯保存聯系人.
    @Test
    /**
     * 測試級聯保存:
     * * 保存客戶 同時 級聯保存聯系人.
      * 在set集合上配置cascade=”save-update”
     */
    public void demo3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        // 保存客戶:
        Customer customer = new Customer();
        customer.setCust_name("陳總");
        // 保存聯系人:
        LinkMan man1 = new LinkMan();
        man1.setLkm_name("小花");

        // 建立關系:
        customer.getLinkMans().add(man1);
        man1.setCustomer(customer);
        
        // 執行保存操作:
        session.save(customer); // TransientObjectException:customer變為持久態對象,man 還是瞬時態對象.
        // session.save(man1);
        
        tx.commit();
    }

    2.保存聯系人的同時保存相對應的客戶

     1)在聯系人映射文件的<one-to-many>標簽中添加cascade=save-update屬性

 

<many-to-one name="customer" class="com.clj.domain.Customer" column="lkm_cust_id" cascade=”save-update”/>

 

     2) 編寫相對應的測試類

    @Test
    /**
     * 測試級聯保存:
     * * 保存聯系人 級聯 保存客戶.
      * 在many-to-one上配置cascade=”save-update”
     */
    public void demo4(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        // 保存客戶:
        Customer customer = new Customer();
        customer.setCust_name("肖總");
        // 保存聯系人:
        LinkMan man1 = new LinkMan();
        man1.setLkm_name("小嬌");

        // 建立關系:
        customer.getLinkMans().add(man1);
        man1.setCustomer(customer);
        
        // 執行保存操作:
        // session.save(customer); // TransientObjectException:customer變為持久態對象,man 還是瞬時態對象.
        session.save(man1);
        
        tx.commit();
    }

九、級聯刪除

     需求:刪除客戶的時候同時刪除客戶的聯系人

     1)在客戶映射文件下的<set>標簽中配置cascade=delete屬性

        2 )  編寫相對應的測試類 

@Test
    /**
     * 測試級聯刪除
     * 刪除客戶的時候 刪除聯系人:
     * 需要在Customer.hbm.xml中set標簽上配置cascade="delete"
     */
    public void demo6(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        Customer customer = session.get(Customer.class, 1l);
        session.delete(customer);
        
        // 不能級聯刪除的.
        /*Customer customer = new Customer();
        customer.setCust_id(1l);
        
        session.delete(customer);*/
        tx.commit();
    }

 

    需求:刪除聯系人的時候同時刪除客戶

     1)在聯系人映射文件下的<one-to-many>標簽中配置cascade=delete屬性

        2)編寫測試類

 

@Test
    /**
     * 測試級聯刪除
     * 刪除聯系人 同時刪除 客戶:
     * 需要在LinkMan.hbm.xml中many-to-one標簽上配置cascade="delete"
     */
    public void demo7(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        LinkMan linkman = session.get(LinkMan.class, 1l);
        
        session.delete(linkman);
        
        tx.commit();
    }

 

    補充:

    級聯操作時,時常會因為雙向關聯會產生許多冗余的數據,因為快照機制,在數據處理時進行數據的比對。

    此時得用到inverse="true"屬性

    

@Test
    /**
     * 更改聯系人所屬的客戶
     * * 雙向關聯 會產生多余的SQL:
     */
    public void demo8(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        LinkMan linkman = session.get(LinkMan.class, 5l);
        
        Customer customer = session.get(Customer.class, 4l);
        // 雙向關聯:
        linkman.setCustomer(customer);
        customer.getLinkMans().add(linkman);
        
        tx.commit();
    }

   此時,在客戶映射文件中添加inverse="trues"屬性,就可避免數據冗余(一的一方放棄主鍵維護)

<set name="linkmans" cascade="save-update" inverse="true">
            <!-- 需要出現子標簽 -->
            <key column="lkm_cust_id"/>
            <one-to-many class="com.clj.domain.Linkman"/>
        </set>

十、Hibernate框架查詢方式

     1.OID檢索方式(通過唯一主鍵進行查詢)

      語法:session.get(對象名.class,主鍵Id);

/**
     * OId的方式查詢與對象導航的方式(兩者特點:只能查詢到一條數據)
     * 查詢客戶
     */
    @Test
    public void run1(){
        //先查詢1號客戶
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查詢1:通過OId的方式查詢客戶(通過主鍵查詢)
        //先是有OID的方式查詢客戶
        Customer c=session.get(Customer.class,1L);
        System.out.println("===================");
        //查看該客戶聯系人的集合
        //查詢2:對象導航的方式
        System.out.println(c.getLinkmans().size());
        tr.commit();
    }

     2.對象導航方式

       語法:new User().getRole().getRname()

/**
     * OId的方式查詢與對象導航的方式
     * 查詢聯系人,屬於某個客戶
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Linkman man=session.get(Linkman.class,5L);
        System.out.println("====================");
        System.out.println(man.getCustomer().getCust_name());
        tr.commit();
    }

     3.HQL的查詢方式

     1) HQL(Hibernate Query Language) 是面向對象的查詢語言, 它和 SQL 查詢語言有些相似

      2)HQL 查詢語句是面向對象的,Hibernate負責解析HQL查詢語句, 然后根據對象-關系映射文件中的映射信息, 把 HQL 查詢語句翻譯成相應的 SQL 語句.

/**
 * HQL的檢索方式
 * @author Administrator
 *
 */
public class Demo2 {
    /**
     * 基本演示
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建查詢接口
        Query query=session.createQuery("from Customer");
        //調用list()方法,查詢
        List<Customer> list=query.list();
        for(Customer customer:list){
            System.out.println(customer);
        }
        tr.commit();
    }
    /**
     * 支持方法鏈的編程風格
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建HQL的查詢接口
        List<Customer> list=session.createQuery("from Customer").list();
        for(Customer customer:list){
            System.out.println(customer);
        }
        tr.commit();
    }
    /**
     * 使用別名的方式
     */
    @Test
    public void run3(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建HQL的查詢接口
        //注意:這里不能用select * from Customer框架中沒有這個語法
        List<Customer> list=session.createQuery("select c from Customer c").list();
        for(Customer customer:list){
            System.out.println(customer);
        }
        tr.commit();
    }
    /**
     * 排序查詢
     * SQL:order by 字段 asc/desc;
     * HQL:關鍵字是一樣的,都是有order by 屬性
     */
    @Test
    public void run4(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查詢聯系人
        //注意:這里是order by+屬性(不是字段)
        List<Linkman> list=session.createQuery("from Linkman w order by w.km_id desc").list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * HQL分頁查詢的兩個方法
     * setFirstResult(a)  --從哪條記錄開始,如果查詢是從第一條開始,值是0
     * setMaxResults(b)      --沒頁查詢的記錄條數
     */
    @Test
    public void run5(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Query query=session.createQuery("from Linkman");
        //分頁查詢,調用方法,查詢第一頁的數據1-3條
        /*query.setFirstResult(0);
        query.setMaxResults(3);*/
        //查詢第二頁的數據
        query.setFirstResult(3);//計算公式:(當前頁-1)*pageSize=3
        query.setMaxResults(3);
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 按條件進行查詢
     */
    @Test
    public void run6(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //Query query=session.createQuery("from Linkman l where l.lkm_gender=?");
        Query query=session.createQuery("from Linkman l where l.lkm_id>? and l.lkm_gender=?");
        //傳入
        //query.setString(0,"男");
        //通用符setParameter(Interger,object)無須考慮問號的參數類型
        query.setParameter(0,3L);
        query.setParameter(1,"女");
        
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 按條件進行查詢
     * 占位符的方式
     */
    @Test
    public void run7(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Query query=session.createQuery("from Linkman l where l.lkm_gender=:gender");
        //傳入
        query.setString("gender","女");
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 指定字段查詢
     */
    @Test
    public void run8(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Query query=session.createQuery("select lkm_name,lkm_gender from Linkman");
        List<Object[]> list=query.list();
        for(Object[] objects:list){
            System.out.println(Arrays.toString(objects));
        }
        tr.commit();
    }
    /**
     * 投影查詢:只查詢幾個字段,不是所有的字段
     * 第一步:需要在JavaBean類提供對應的構造方法(指定的有參和無參)
     * 第二步:HQL語句發生變化
     */
    @Test
    public void run9(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Query query=session.createQuery("select new Linkman(lkm_name,lkm_gender) from Linkman");
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 聚合函數:count() avg() max() min()
     */
    @Test
    public void run10(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查詢所有的聯系人的數量
        //Number是所有數值類型的父類
        List<Number> list=session.createQuery("select count(w) from Linkman w").list();
        //通過下標值進行取值
        Long count=list.get(0).longValue();//轉為long類型
        System.out.println("數量為:"+count);
        
        tr.commit();
    }
    /**
     * 聚合函數:求數量
     * sum(屬性必須為數值類型)
     */
    @Test
    public void run11(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查詢所有的聯系人的數量
        //Number是所有數值類型的父類
        List<Number> list=session.createQuery("select sum(lkm_id) from Linkman").list();
        //通過下標值進行取值
        Long count=list.get(0).longValue();//轉為long類型
        System.out.println("數量為:"+count);
        
        tr.commit();
    }
    
}

 

      4.QBC檢索方式

        1)QBC:Query By Criteria  按條件進行查詢

       2)條件查詢的方法:

 *    * Restrictions.eq           -- 相等
        * Restrictions.gt           -- 大於號
        * Restrictions.ge           -- 大於等於
        * Restrictions.lt           -- 小於
        * Restrictions.le           -- 小於等於
        * Restrictions.between      -- 在之間
        * Restrictions.like         -- 模糊查詢
        * Restrictions.in           -- 范圍
        * Restrictions.and          -- 並且
        * Restrictions.or           -- 或者

       3)測試代碼 

/**
 * QBC的查詢(條件查詢)
 * @author Administrator
 *
 */
public class Demo3 {
    /**
     * QBC的基本入門查詢
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建QBC查詢接口
        Criteria criteria=session.createCriteria(Customer.class);
        List<Customer> list=criteria.list();
        for(Customer customer:list){
            System.out.println(customer);
        }
        tr.commit();
        
    }
    /**
     * QBC的基本查詢
     * 排序查詢,調用的方法
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建QBC查詢接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //調用排序的方法,addOrder(),這里演示降序排序
        criteria.addOrder(Order.desc("lkm_id"));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
        
    }
    /**
     * QBC分頁的方法和HQL分頁的方法一樣的
     */
    @Test
    public void run3(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建QBC查詢接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //調用排序的方法,addOrder(),這里演示降序排序
        criteria.addOrder(Order.desc("lkm_id"));
        //設置分頁的方法
        criteria.setFirstResult(0);
        criteria.setMaxResults(3);
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
        
    }
    /**
     * QBC的條件查詢
     */
    @Test
    public void run4(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建QBC查詢接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //使用方法添加條件
        criteria.add(Restrictions.eq("lkm_gender","男"));
        //ge大於等於
        criteria.add(Restrictions.ge("lkm_id",3L));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
        
    }
    /**
     * in查詢
     */
    @Test
    public void run5(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建QBC查詢接口
        Criteria criteria=session.createCriteria(Linkman.class);
        List<Long> params=new ArrayList<Long>();
        params.add(1L);
        params.add(2L);
        params.add(3L);
        //使用in,方法查詢(當然,這里不一定弄過集合,可以整個數組也行)
        criteria.add(Restrictions.in("lkm_id",params));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * or查詢
     */
    @Test
    public void run6(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建QBC查詢接口
        Criteria criteria=session.createCriteria(Linkman.class);
        criteria.add(Restrictions.or(Restrictions.eq("lkm_gender", "女"),Restrictions.gt("lkm_id",3L)));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 判斷值是否為空
     */
    @Test
    public void run7(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建QBC查詢接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //找所有的lkm_email是空的值
        //注意:isEmpty是判斷集合是否為空
        criteria.add(Restrictions.isNull("lkm_email"));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 聚合函數的查詢
     */
    @Test
    public void run8(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建QBC查詢接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //設置聚合函數的查詢方式
        List<Number> list=criteria.setProjection(Projections.count("lkm_id")).list();
        Long count=list.get(0).longValue();
        System.out.println("數量為:"+count);
        tr.commit();
    }
    /**
     * 強調問題:select count(*) from 表,又想查select * from 表,存在問題
     */
    @Test
    public void run9(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建QBC查詢接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //設置聚合函數的查詢方式
        criteria.setProjection(Projections.count("lkm_id"));
        List<Number> list=criteria.list();
        Long count=list.get(0).longValue();
        System.out.println("數量為:"+count);
        //再設置一遍setprojection方法
        criteria.setProjection(null);
        List<Linkman> mans=criteria.list();
        for(Linkman linkman:mans){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 演示離線條件對象
     * 創建條件查詢時不需要session
     * 只有真正涉及到查詢數據,調用數據庫時才需要用到session
     */
    @Test
    public void run10(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建離線條件查詢的對象
        DetachedCriteria criteria=DetachedCriteria.forClass(Linkman.class);
        //去添加查詢條件了
        criteria.add(Restrictions.eq("lkm_gender","女"));
        //查詢
        List<Linkman> list=criteria.getExecutableCriteria(session).list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
}

    5.SQL查詢方式

public class Demo4 {
    /**
     * 測試SQL語句的查詢
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建的是SQL的查詢的接口
        SQLQuery query=session.createSQLQuery("select * from cst_linkman");
        //查詢數據(注意:這里泛型是Object,不是對象,因為這里返回的數據時表的數據,不是對象)
        List<Object[]> list=query.list();
        for(Object[] object:list){
            System.out.println(Arrays.toString(object));
        }
        tr.commit();
    }
    /**
     * 把數據封裝到對象中
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //創建的是SQL的查詢的接口
        SQLQuery query=session.createSQLQuery("select * from cst_linkman");
        //通過方法設置
        query.addEntity(Linkman.class);
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
}

    6.HQL多表查詢

/**
 * HQL的多表查詢
 * @author Administrator
 *
 */
public class Demo5 {
    /**
     * 查詢的客戶,客戶和聯系人有關聯
     * select * from cst_customer c,cst_linkman l when c.id=l.id;
     */
     @Test
     public void run1(){
         Session session=HibernateUtils.getCurrentSession();
         Transaction tr=session.beginTransaction();
         //內連接的查詢
         //這里的linkmans關聯的是Customer類中集合屬性名
         Query query=session.createQuery("from Customer c inner join c.linkmans");
         //這里默認放回值是數組
         List<Object[]> list=query.list(); 
         for(Object[] obj:list){
             System.out.println(Arrays.toString(obj));
         }
         tr.commit();
     }
     /**
      * 數據默認返回的數組,把數據封裝到對象中
      * 提供關鍵字:fetch 迫切連接
      * 缺點:數據有冗余,有重復數據
      */
     @Test
     public void run2(){
         Session session=HibernateUtils.getCurrentSession();
         Transaction tr=session.beginTransaction();
         //內連接的查詢
         //這里的linkmans關聯的是Customer類中集合屬性名
         Query query=session.createQuery("from Customer c inner join fetch c.linkmans");
         //這里默認放回值是數組
         List<Customer> list=query.list(); 
         for(Customer customer:list){
             System.out.println(customer);
         }
         tr.commit();
     }
    /**
     * 解決數據的重復的問題
     */
     @Test
     public void run3(){
         Session session=HibernateUtils.getCurrentSession();
         Transaction tr=session.beginTransaction();
         //內連接的查詢
         Query query=session.createQuery("from Customer c inner join fetch c.linkmans");
         List<Customer> list=query.list(); 
         //手動解決,編程中都是用這種方式解決重復的問題
         Set<Customer> set=new HashSet<Customer>(list);
         for(Customer customer:set){
             System.out.println(customer);
         }
         tr.commit();
     }
}

十一、Hibernate之延遲加載

     1.什么是延遲加載?

       延遲加載先獲取到代理對象,當真正使用到該對象中的屬性的時候,才會發送SQL語句,是Hibernate框架提升性能的方式

    2.Session對象的load方法默認就是延遲加載

    3.hibernate框架默認形式就是延遲加載,如果想取消此功能,需添加lazy="false"屬性

/**
 * 演示的延遲加載,提升程序的性能
 * 即當真正需要數據時才進入數據庫查詢
 * @author Administrator
 *
 */
public class Demo6 {
    /**
     * 類級別的延遲加載
     * 需要使用session.load()默認情況使用的延遲加載
     * 只有當查詢對象的屬性時才調用數據庫進行數據的查詢
     * 默認情況下配置文件中的延遲加載默認值為true(即lazy="true")
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //Customer c1=session.get(Customer.class,1L);//原始在此時就調用數據庫
        Customer c1=session.load(Customer.class,1L);
        System.out.println("=====================");
        System.out.println(c1.getCust_name());//此時才調用數據庫查詢數據
        tr.commit();
    }
    /**
     * 在調用load方法情況下怎么取消延遲加載
     * 1.在配置文件中設置lazy="false"
     * 2.重新初始化對象
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //Customer c1=session.get(Customer.class,1L);//原始在此時就調用數據庫
        Customer c1=session.load(Customer.class,1L);
        //把c1對象初始化
        Hibernate.initialize(c1);
        System.out.println("=====================");
        System.out.println(c1.getCust_name());//此時才調用數據庫查詢數據
        tr.commit();
    }
    /**
     * 關聯級別的延遲加載
     * 說的是客戶下的聯系人的集合
     */
    @Test
    public void run3(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //先查詢1號客戶
        Customer c1=session.get(Customer.class,1L);//默認情況下是延遲加載,此時只查詢客戶,不會查詢聯系人
        System.out.println("=================");
        //看客戶下所有的聯系人
        System.out.println("聯系人"+c1.getLinkmans().size());
        tr.commit();
    }
    /**
     * fetch屬性能解決的問題
     */
    @Test
    public void run4(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        List<Customer> list=session.createQuery("from Customer").list();
        int count=0;
        for(Customer customer:list){
            count++;
            System.out.println("客戶"+count+"的聯系人數量為"+customer.getLinkmans().size());
        }
        tr.commit();
    }
}

 

    

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM