Hibernate框架——入門基礎筆記(詳細介紹)

一、hibernate 基礎

1、ORM 框架

  • 對象關係映射(Object Relational Mapping,簡稱ORM)是通過使用描述對象和數據庫之間映射的元數據,將面嚮對象語言程序中的對象自動持久化到關係數據庫中。
  • ORM(Object Relational Mapping)框架採用元數據來描述對象與關係映射的細節,元數據一般採用XML格式,並且存放在專門的對象一映射文件中。
    在這裏插入圖片描述

2、hibernate

  • Hibernate是一個開放源代碼的對象關係映射框架,它對JDBC進行了非常輕量級的對象封裝,它將POJO與數據庫表建立映射關係,是一個全自動的orm框架。
  • hibernate可以自動生成SQL語句,自動執行,使得Java程序員可以隨心所欲的使用對象編程思維來操縱數據庫。
  • Hibernate可以應用在任何使用JDBC的場合,既可以在Java的客戶端程序使用,也可以在Servlet/JSP的Web應用中使用,最具革命意義的是,Hibernate可以在應用EJB的JaveEE架構中取代CMP,完成數據持久化的重任。
  • Hibernate是輕量級JavaEE應用的持久層解決方案,是一個關係數據庫ORM框架
  • ORM 就是通過將Java對象映射到數據庫表,通過操作Java對象,就可以完成對數據表的操作
  • Hibernate提供了對關係型數據庫增刪改成操作
    在這裏插入圖片描述

3、hibernate 的優點

  • Hibernate對JDBC訪問數據庫的代碼做了封裝,大大簡化了數據訪問層繁瑣的重複性代碼
  • Hibernate是一個基於jdbc的主流持久化框架,是一個優秀的orm實現,它很大程度的簡化了dao層編碼工作 session.save(User);
  • Hibernate使用java的反射機制
  • Hibernate的性能非常好,因爲它是一個輕量級框架。映射的靈活性很出色。它支持很多關係型數據庫,從一對一到多對多的各種複雜關係

二、案例

在這裏插入圖片描述
工具:Meven、 IntelliJ IDEA、MySQL

第一步:

引入jar 包:mysql-connector-javahibernate-corejunit

第二步:編寫JavaBean對象、映射文件

JavaBean 對象——User.java

package cn.lemon.domain;

public class User {
    private Integer id;
    private String username;
    private String password;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

映射文件——User.hbm.xml

<!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:映射的實體類;table:數據庫表-->
    <class name="cn.lemon.domain.User" table="user">
        <!--映射主鍵字段,name = id 表示:主鍵字段-->
        <id name="id">
            <!--數據庫裏的id-->
            <column name="id_"/>
            <!-- 主鍵生成策略:
                * identity 表示自增的主鍵-->
            <generator class="identity"/>
        </id>
        <!--映射其他的字段;property 裏的 name 表示實體類裏的字段; column 裏的 name 表示數據庫表的字段-->
        <property name="username">
            <column name="username_"/>
        </property>
        <property name="password">
            <column name="password_"/>
        </property>
    </class>
</hibernate-mapping>
第三步:編寫核心配置文件(hibernate.cfg.xml)用來配置獲得鏈接等參數
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <!-- SessionFactory,相當於連接池配置 -->
    <session-factory>
        <property name="connection.url">jdbc:mysql:///db_hibernate</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.username">root</property>
        <property name="connection.password">lemon</property>
        <property name="hbm2ddl.auto">update</property>

        <!-- 方言:指定當前hibernate使用的數據庫 -->
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

        <!-- 添加映射文件 -->
        <mapping resource="cn/lemon/domain/User.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
第四步:測試
package cn.lemon.test;

import cn.lemon.domain.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class HibernateTest {
    @Test
    public void test01() {
        User user = new User();
        user.setUsername("詹姆斯");
        user.setPassword("123321");

        Configuration cfg = new Configuration().configure("cn/lemon/domain/hibernate.cfg.xml");//加載配置文件獲得核心配置對象,默認讀取 classpath/hibernate.cfg.xml
        SessionFactory sf = cfg.buildSessionFactory(); //獲得工廠 SessionFactory,相當於連接池
        Session session = sf.openSession();//獲得會話session,相當於鏈接Connection
        Transaction tx = session.beginTransaction(); //啓動事務,hibernate和mybatis都是自動提交事務關閉

        session.save(user); //持久化操作

        tx.commit();//提交事務
        session.close();//釋放資源,關閉 Session
        sf.close();//釋放資源,關閉工廠類
    }
}

三、API 詳解

1、體系結構

在這裏插入圖片描述

2、Configuration 配置對象
  • hibernate 核心配置文件種類
  • hibernate.cfg.xml 通常使用xml配置文件,可以配置內容更豐富。
  • hibernate.properties 用於配置key/value 形式的內容,key不能重複的。配置有很多的侷限性。一般不用。

1、提供構造 new Configuration() hibernate將自動加載 hibernate.properties文件
hibernate.properties文件必須存放在類路徑(src)下
2、提供方法 configure() 將加載src下的hibernate.cfg.xml
3、擴展api

  • configure(String) 加載指定目錄下的 xml文件

4、手動加載配置文件

  • config.addResource(“com/lxs/a_hello/User.hbm.xml”);// 手動加載指定的配置文件
  • config.addClass(User.class);// 手動加載指定類,對應的映射文件 User–> User.hbm.xml
3、SessionFactory 工廠
  • SessionFactory 相當於java web連接池,用於管理所有session
  • 獲得方式:config.buildSessionFactory();
  • sessionFactory hibernate緩存配置信息 (數據庫配置信息、映射文件,預定義HQL語句 等)
  • SessionFactory線程安全,可以是成員變量,多個線程同時訪問時,不會出現線程併發訪問問題。
  • 提供api:
    • factory.openSession();//打開一個新的會話 session,openSession需要調用close方法關閉session;
    • factory.getCurrentSession();//獲得當前線程中綁定的會話session;hibernate支持,將創建的session綁定到本地線程中,底層使用ThreadLocal,在程序之間共享session
      1、必須在hibernate.cfg.xml 配置<property name="hibernate.current_session_context_class">thread</property>
      2、如果提交或回滾事務,底層將自動關閉session

示例代碼:

package cn.lemon.b_api;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class SessionFactoryTest {
    @Test
    public void test(){
        User user = new User();
        user.setUsername("詹姆斯");
        user.setPassword("123321");

        Configuration cfg = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");//加載配置文件獲得核心配置對象,默認讀取 classpath/hibernate.cfg.xml
        SessionFactory sf = cfg.buildSessionFactory(); //獲得工廠 SessionFactory,相當於連接池
        //Session session = sf.openSession();//獲得會話session,相當於鏈接Connection

        /**獲得當前線程中綁定的會話session;hibernate支持,將創建的session綁定到本地線程中,底層使用ThreadLocal,在程序之間共享session
        1、必須在hibernate.cfg.xml 配置`<property name="hibernate.current_session_context_class">thread</property>`
        2、如果提交或回滾事務,底層將自動關閉session*/
        Session session = sf.getCurrentSession();
        Transaction tx = session.beginTransaction(); //啓動事務,hibernate和mybatis都是自動提交事務關閉

        session.save(user); //持久化操作

        tx.commit();//提交事務
        //session.close();//釋放資源,關閉 Session
        sf.close();//釋放資源,關閉工廠類
    }
}
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!--核心配置文件-->
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/db_hibernate</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">lemon</property>

        <!--方言dialect:指定hibernate 使用的數據庫-->
        <property name="dialect">org.hibernate.dialect.MySQL55Dialect</property>

        <!--與本地線程綁定-->
        <property name="hibernate.current_session_context_class">thread</property>

        <!--映射文件-->
        <mapping resource="cn/lemon/b_api/User.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
4、Session 會話
  • Session 相當於 JDBC的 Connection
  • 通過session操作PO對象 --增刪改查
  • session單線程,線程不安全,不能編寫成成員變量。
  • session api
    • save 保存
    • update 更新
    • delete 刪除
    • get 通過id查詢,如果沒有 null
    • load 通過id查詢,如果沒有拋異常
    • createQuery("hql") 獲得Query對象
    • createCriteria(Class) 獲得Criteria對象
5、Transaction 事務
  • 開啓事務 beginTransaction()
  • 獲得事務 getTransaction()
  • 提交事務 commit()
  • 回滾事務 rollback()
try{
   //開啓
   //session操作
   //提交
} catch(e){
   //回滾
}

擴展:不需要手動的管理事務,之後所有的事務管理都交予spring。
示例代碼:

package cn.lemon.b_api;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.util.List;

public class UserDao {
    /**
     * 添加
     *
     * @param user
     * @return
     */
    public Integer addTest(User user) {//hibernate 返回的是添加的主鍵,而 mybatis 返回的是影響的行數
        Configuration configuration = null;
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction transaction = null;
        Integer result = null;

        try {
            configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
            sessionFactory = configuration.buildSessionFactory();
            session = sessionFactory.getCurrentSession();
            transaction = session.beginTransaction();

            result = (Integer) session.save(user);

            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();//如果有異常,回滾事務
        } finally {
            sessionFactory.close();
        }
        return result;
    }

    /**
     * 修改
     * @param user
     */
    public void updateTest(User user) {//修改是沒有返回值的
        Configuration configuration = null;
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction transaction = null;

        try {
            configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
            sessionFactory = configuration.buildSessionFactory();
            session = sessionFactory.getCurrentSession();
            transaction = session.beginTransaction();

            session.update(user);

            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();//如果有異常,回滾事務
        } finally {
            sessionFactory.close();
        }
    }

    /**
     * 刪除
     *
     * @param user user的主鍵不能爲空
     */
    public void deleteTest(User user) {//修改是沒有返回值的
        Configuration configuration = null;
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction transaction = null;

        try {
            configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
            sessionFactory = configuration.buildSessionFactory();
            session = sessionFactory.getCurrentSession();
            transaction = session.beginTransaction();

            session.delete(user);

            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();//如果有異常,回滾事務
        } finally {
            sessionFactory.close();
        }
    }

    /**
     * 根據 id 查詢
     * @param id
     * @return
     */
    public User findByIdTest(Integer id) {
        User user = null;
        Configuration configuration = null;
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction transaction = null;

        try {
            configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
            sessionFactory = configuration.buildSessionFactory();
            session = sessionFactory.getCurrentSession();
            transaction = session.beginTransaction();

            user = (User) session.get(User.class, id);//get 方法與 load 方法的區別就是 get 不使用緩存,而load 使用緩存

            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();//如果有異常,回滾事務
        } finally {
            sessionFactory.close();
        }
        return user;
    }

    /**
     * 根據 id 查詢,load 使用緩存
     * @param id
     * @return
     */
    public User findByIdTest2(Integer id) {
        User user = null;
        Configuration configuration = null;
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction transaction = null;

        try {
            configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
            sessionFactory = configuration.buildSessionFactory();
            session = sessionFactory.getCurrentSession();
            transaction = session.beginTransaction();

            user = (User) session.load(User.class, id);

            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();//如果有異常,回滾事務
        } finally {
            //sessionFactory.close();
        }
        return user;
    }

    /**
     * 查詢所有
     * @return
     */
    public List<User> findAll() {
        List<User> userList = null;
        Configuration configuration = null;
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction transaction = null;//查詢所有,有事務也行,沒有也行

        try {
            configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
            sessionFactory = configuration.buildSessionFactory();
            session = sessionFactory.getCurrentSession();
            transaction = session.beginTransaction();
            Query query = session.createQuery("from User");
            userList = query.list();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();//如果有異常,回滾事務
        } finally {
            sessionFactory.close();
        }
        return userList;
    }
}
package cn.lemon.b_api;

import org.junit.Test;

import java.util.List;

public class UserTest {
    UserDao userDao = new UserDao();

    @Test
    public void testAdd() {//測試添加
        User user = new User();
        user.setUsername("馬雲");
        user.setPassword("123");
        userDao.addTest(user);
    }

    @Test
    public void deleteTest() {//測試刪除
        User user = new User();
        user.setId(15);
        userDao.deleteTest(user);
    }

    @Test
    public void updateTest() {//測試修改
        User user = new User();
        user.setId(14);
        user.setUsername("馬化騰");
        user.setPassword("123");
        userDao.updateTest(user);
    }

    @Test
    public void findByIdTest() {//測試 get 查找
        User user = userDao.findByIdTest(14);
        System.out.println(user.getId() + "\t" + user.getUsername() + "\t" + user.getPassword());

        User user2 = userDao.findByIdTest(123);//get 方法加載不存在的id時,get 返回 null,而load 會報錯
        System.out.println(user2);//返回 null
    }

    @Test
    public void finfById2Test() {//測試 load 查找
        User user = userDao.findByIdTest2(14);//這是load 方法加載,使用類延遲加載(懶加載),不能關閉Session,如果關閉了會報錯
        System.out.println(user);
    }

    @Test
    public void findAll() {//測試查查詢所有
        List<User> list = userDao.findAll();
        for (User user : list) {
            System.out.println(user.getId() + "\t" + user.getUsername() + "\t" + user.getPassword());
        }
    }
}

在上面的代碼中,有太多重複的代碼,所以需要簡化一下 UserDao,需要一個工具類 HibernateUtils

package cn.lemon.b_api.utils;

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

public class HibernateUtils {
    private static Configuration configuration;
    private static SessionFactory sessionFactory;//會話工廠,整個程序只有一個

    static {
        configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");//第一步:加載配置文件
        sessionFactory = configuration.buildSessionFactory();//第二步:獲得工廠,相當於連接池
        //第三步:addShutdownHook:捕獲虛擬機關閉,當關閉虛擬機時,釋放 SessionFactory 工廠
        //匿名內部類的寫法:
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("虛擬機關閉,釋放資源..........");
                sessionFactory.close();//關閉 SessionFactory 工廠
            }
        }));
        // lanmda 表達式的寫法
        /**
        Runtime.getRuntime().addShutdownHook(new Thread(() ->{
            System.out.println("虛擬機關閉,釋放資源..........");
            sessionFactory.close();//關閉 SessionFactory 工廠
        }));*/
    }

    public static Session openSession() {//獲得一個新的 Session
        return sessionFactory.openSession();
    }

    public static Session getCurrentSession() {//獲得當前線程中綁定的 Session (注意:必須配置)
        return sessionFactory.getCurrentSession();
    }
}

四、核心配置文件詳解

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!--Hibernate 的核心配置文件-->
<hibernate-configuration>
    <!--session-factory:相當於連接池的配置-->
    <session-factory>
        <!--基本 4 項:用於連接數據庫,配置連接參數-->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/db_hibernate</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">lemon</property>

        <!--與本地線程綁定,使用 getCurrentSession()-->
        <property name="hibernate.current_session_context_class">thread</property>

        <!--方言dialect:指定 hibernate 使用的數據庫,爲不同的數據庫不同的版本生成 SQL 語句提供依據-->
        <property name="dialect">org.hibernate.dialect.MySQL55Dialect</property>

        <!--可以顯示控制檯操作數據庫的語句-->
        <property name="hibernate.show_sql">true</property>

        <!--格式化語句-->
        <property name="format_sql">true</property>

        <!--給語句註釋-->
        <property name="use_sql_comments">true</property>

        <!--
        自動創建表
        * sessionFactory:產生時,自動根據映射產生表
        * 取值:
        *   * update:
                1、如果表不存在,將創建表。
                2、如果表已經存在,通過hbm映射文件更新表(添加)。(映射文件必須是數據庫對應)
                3、表中的列可以多,不負責刪除。
            * create :
                如果表存在,先刪除,再創建。程序結束時,之前創建的表不刪除。
            * create-drop:與create幾乎一樣。如果factory.close()執行,將在JVM關閉同時,將創建的表刪除了。(測試)
            * validate:校驗 hbm映射文件 和 表的列是否對應,如果對應正常執行,如果不對應拋出異常。(測試)
        -->
        <property name="hibernate.hbm2ddl.auto">update</property>

        <!--配置映射文件-->
        <mapping resource="cn/lemon/c_config/domain/User.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

五、Hibernate 中持久化類(如:User 類)和映射文件

1、編寫規則
  • 提供一個無參數 public訪問控制符的構造器
  • 提供一個標識屬性,映射數據表主鍵字段
  • 所有屬性提供public訪問控制符的 set get 方法(javaBean)
  • 標識屬性應儘量使用基本數據類型的包裝類型
  • 不要用final修飾實體 (將無法生成代理對象進行優化)
2、基本數據類型與包裝數據類型
  • 基本數據類型和包裝類型對應hibernate的映射類型相同
  • 基本類型無法表達null、數字類型的默認值爲0。
  • 包裝類默認值是null。當對於默認值有業務意義的時候需要使用包裝類。
3、類型對應

在這裏插入圖片描述

4、Hibernate 映射文件(如:User.hbm.xml)
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<!--User 的 hibernate 映射文件-->
<!--
    package:用於配置 PO 類所在的包
-->
<hibernate-mapping package="cn.lemon.test.domain">
    <!--
        class:配置 PO類 和 表 之間對應關係
        name:PO類全限定類名:如果配置 package,name的取值可以是簡單類名 name="User"
        table : 數據庫對應的表名
		dynamic-insert="false" 是否支持動態生成insert語句
		dynamic-update="false" 是否支持動態生成update語句
				如果設置true,hibernate底層將判斷提供數據是否爲null,如果爲null,insert或update語句將沒有此項。
    -->
    <class name="cn.lemon.test.domain.User" table="user" dynamic-insert="false" dynamic-update="false">
        <!--
            <id>配置主鍵
				name:屬性名稱
				access="" 設置使用屬性還是字段
				column=""  表的列名
				length=""  長度
				type="" 類型
			<generator> class屬性用於設置主鍵生成策略
			    1.increment 由hibernate自己維護自動增長。底層通過先查詢max值,再+1策略;不建議使用,存在線程併發問題
				2.identity hibernate底層採用數據庫本身自動增長列。例如:mysql auto_increment;建議使用
				3.sequence hibernate底層採用數據庫序列。例如:oracle 提供序列
				4.native 根據底層數據庫的能力選擇(自動識別數據庫) identity(Mysql)、sequence(Oracle)
                    以上策略使用整形,long, short 或者 int 類型
				5.uuid 採用Java的UUID類產生字符串唯一值
                6.guid 採用數據庫函數生成32位隨機字符串
				    以上策略 代理主鍵,有hibernate維護。
				7.assigned 自然主鍵,由程序自己維護。
        -->
        <id name="id">
            <column name="id_"/>
            <generator class="identity"/><!--主鍵策略-->
        </id>
        <!--
            name : PO類的屬性
			column : 表中的列名,默認name的值相同
			type:表中列的類型。默認hibernate自己通過getter獲得類型,一般情況不用設置
			length : 列的長度。默認值:255
			not-null : 是否爲null
			unique : 是否唯一
			access:設置映射使用PO類屬性或字段
					property : 使用PO類屬性,必須提供setter、getter方法
					field : 使用PO類字段,一般很少使用。
			insert 生成insert語句時,是否使用當前字段。
			update 生成update語句時,是否使用當前字段。
					默認情況:hibernate生成insert或update語句,使用配置文件所有項
		    注意:配置文件如果使用關鍵字,列名必須使用重音符
        -->
        <property name="username">
            <column name="username_"/>
        </property>
        <property name="password">
            <column name="password_"/>
        </property>
        <property name="birthday">
            <column name="birthday_" sql-type="datetime"></column>
        </property>
    </class>
</hibernate-mapping>

六、創建 BaseDao,重用 Dao 的 CRUD 操作

工具類

package cn.lemon.d_refactor.dao;

import cn.lemon.d_refactor.utils.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;

import java.io.Serializable;
import java.util.List;

public class BaseDao {
    public <T> Serializable add(T object) {//添加
        Serializable result = null;
        Session session = null;
        Transaction transaction = null;

        try {
            session = HibernateUtils.openSession();
            transaction = session.beginTransaction();
            result = session.save(object);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        } finally {
            session.close();
        }
        return result;
    }

    public <T> void update(T object) {//修改
        Session session = null;
        Transaction transaction = null;

        try {
            session = HibernateUtils.openSession();
            transaction = session.beginTransaction();
            session.update(object);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        } finally {
            session.close();
        }
    }

    public <T> void delete(T object) {//刪除
        Session session = null;
        Transaction transaction = null;

        try {
            session = HibernateUtils.openSession();
            transaction = session.beginTransaction();
            session.delete(object);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        } finally {
            session.close();
        }
    }

    public <T> T get(Class<T> c, Serializable id) {//get查詢單個
        T object = null;
        Session session = null;
        Transaction transaction = null;

        try {
            session = HibernateUtils.openSession();
            transaction = session.beginTransaction();
            object = (T) session.get(c, id);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        } finally {
            session.close();
        }
        return object;
    }

    public <T> T load(Class<T> c, Serializable id) {//load查詢單個
        T object = null;
        Session session = null;
        Transaction transaction = null;

        try {
            session = HibernateUtils.openSession();
            transaction = session.beginTransaction();
            object = (T) session.load(c, id);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        } finally {
            session.close();
        }
        return object;
    }

    public List list(String hql) {//查詢所有
        List list = null;
        Session session = null;
        try {
            session = HibernateUtils.openSession();
            Query query = session.createQuery(hql);
            list = query.list();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
        return list;
    }
}
package cn.lemon.d_refactor.dao;

import cn.lemon.d_refactor.domain.Student;

import java.util.List;

public class StudentDao extends BaseDao {
    /**
     * 增加
     * @param student
     */
    public void add(Student student) {
        super.add(student);
    }

    /**
     * 修改
     * @param student
     */
    public void update(Student student) {
        super.update(student);
    }

    /**
     * 刪除
     * @param student
     */
    public void delete(Student student) {
        super.delete(student);
    }

    /**
     * get加載
     * @param id
     * @return
     */
    public Student get(String id) {
        return super.get(Student.class, id);
    }

    /**
     * load加載
     * @param id
     * @return
     */
    public Student load(String id) {
        return super.load(Student.class, id);
    }

    /**
     * query查詢
     * @return
     */
    public List<Student> queryList() {
        return (List<Student>) super.list("from Student");
    }
}

測試類

package cn.lemon.d_refactor.test;

import cn.lemon.d_refactor.dao.StudentDao;
import cn.lemon.d_refactor.domain.Student;
import org.junit.Test;

import java.util.Date;

public class StudentTest {
    StudentDao studentDao = new StudentDao();

    @Test
    public void testAdd() {
        Student student = new Student();
        student.setName("張三丰");
        student.setRegisterDate(new Date());
        studentDao.add(student);
    }

    @Test
    public void testGet() {
        Student student = studentDao.get("abc123");
        System.out.println(student.getName());
    }
}

七、Hibernate 對象狀態

在這裏插入圖片描述

1、瞬時態(臨時態)
  • 獲得:一般都只直接創建(new)
  • 瞬時態 轉換 持久態 一般操作:save方法、saveOrUpdate
  • 瞬時態 轉換 脫管態 一般操作:通過setId方法設置數據
    例如:
    • User user = new User(); //瞬時態
    • user.setUid(1); //脫管態
2、持久態
  • 獲得:查詢操作:get、loat、createQuery、createCriteria 等 獲得都是持久態

    • 執行save之後持久態
    • 執行update之後持久態
  • 持久態 轉換 瞬時態 官方規定執行delete() --民間:刪除態

  • 持久態 轉換 脫管態

    • session沒有記錄
    • session.close () 關閉
    • session.clear() 清除所有
    • session.evict(obj) 清除指定的PO對象
3、託管態(遊離態)
  • 獲得:
    創建、並設置OID的
    通過api獲得
  • 脫管態 轉換 瞬時態
    手動去除OID,設置成默認值
  • 脫管態 轉換 持久態
    一般操作:update()、saveOrUpdate
	@Test
	public void demo01(){
		User user = new User();		//瞬時態
		user.setUsername("jack");
		user.setPassword("1234");	//瞬時態(與oid沒有關係)
		
		Session session = factory.openSession();
		session.beginTransaction();
		
		session.save(user);			//持久態
		//---- 持久態就應該有持久態的行爲(特性)
		
//		user.setUsername("rose");  //持久態對象 被修改後,hibernate將自動生成update語句
//		session.flush();
		
		session.getTransaction().commit();
		session.close();
		System.out.println(user);  //脫管態
	}

八、關聯關係映射——一對多映射

模擬客戶與訂單:一個客戶 -> 多個訂單(Customer -> Order)

第一步:新建 Customer.java 、Order.java 實體類
package cn.lemon.e_onetomany.domain;

import java.util.HashSet;
import java.util.Set;

public class Customer {
    private Integer id;
    private String name;

    private Set<Order> orders = new HashSet<>();/*客戶的多個訂單的 Set 集合*/

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Order> getOrders() {
        return orders;
    }

    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }
}
package cn.lemon.e_onetomany.domain;

public class Order {
    private Integer id;
    private String name;

    private Customer customer;/*關聯屬性:訂單所屬的客戶*/

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}
第二步:新建 Customer.hbm.xml 、Order.hbm.xml 映射文件
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--Customer 的 hibernate 映射文件(一對多中 ”一“ 的一方)-->
<hibernate-mapping>
    <class name="cn.lemon.e_onetomany.domain.Customer" table="customer_">
        <id name="id" type="java.lang.Integer">
            <column name="id_"/>
            <generator class="native"/>
        </id>
        <property name="name" type="string">
            <column name="name_"/>
        </property>
        <!--
            映射一對多,由於實體類裏是 Set,這裏要用 set 映射
            name:關聯屬性名
            key裏的 Column :指定外鍵字段
            one-to-many : 映射的關聯類
        -->
        <set name="orders">
            <key column="cust_id_"/>
            <one-to-many class="cn.lemon.e_onetomany.domain.Order"/>
        </set>
    </class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--Order 的 hibernate 映射文件(一對多中 ”多“ 的一方)-->
<hibernate-mapping>
    <class name="cn.lemon.e_onetomany.domain.Order" table="order_">
        <id name="id" type="java.lang.Integer">
            <column name="id"/>
            <generator class="native"/>
        </id>
        <property name="name">
            <column name="name"/>
        </property>

        <!--多對一
            name:關聯屬性名
            column:外鍵字段,要與 Customer 中的外鍵字段一致
            class : 關聯的類
        -->
        <many-to-one name="customer" column="cust_id_" class="cn.lemon.e_onetomany.domain.Customer"/>
    </class>
</hibernate-mapping>
第三步:測試
package cn.lemon.e_onetomany.test;

import cn.lemon.d_refactor.utils.HibernateUtils;
import cn.lemon.e_onetomany.domain.Customer;
import cn.lemon.e_onetomany.domain.Order;
import org.hibernate.Session;
import org.junit.Test;

public class OnetomanyTest {

    @Test
    public void testCreateTable() {
        HibernateUtils.getCurrentSession();//當sessionFactory產生時產生表結構
    }

    /**
     * 客戶加載,自動加載客戶的訂單
     */
    @Test
    public void testGet() {
        Session session = HibernateUtils.openSession();
        Customer customer = (Customer) session.get(Customer.class, 2);
        System.out.println(customer.getName());
        System.out.println("--------------------------------------");

//		System.out.println(customer.getOrders().size());

        for (Order o : customer.getOrders()) {
            System.out.println(o.getName());
        }
        session.close();
    }

    @Test
    public void testList() {
        Session session = HibernateUtils.openSession();
        session.createQuery("from customer_").list();
    }

    /**
     * 保存訂單
     */
    @Test
    public void demo02(){
        //創建訂單,保存訂單--成功,外鍵爲null
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        Order order = new Order();
        order.setName("檯球");

        //訂單所屬的客戶沒有賦值,外鍵=null
        //第一種賦值
//		Customer c = new Customer();
//		c.setId(4);

        //第二種
        Customer c = (Customer) session.get(Customer.class, 3);

        //設置關聯屬性,讓訂單屬於c(id=4)這個客戶
        order.setCustomer(c);

        session.save(order);
        session.getTransaction().commit();
        session.close();
    }

    /**
     * 保存客戶和訂單:讓客戶(一)維護關聯關係
     * 	  inverse=false:因爲維護關聯關係, 添加客戶時,執行update語句關聯外鍵=客戶的主鍵
     *    inverse=true::因爲不維護關聯關係,添加客戶時,外鍵=null
     *    cascade=save-update:級聯添加和修改,客戶添加,自動客戶管理的訂單
     */
    @Test
    public void demo03(){
        //創建客戶和訂單,客戶關聯訂單,保存客戶?
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        //客戶和訂單
        Customer customer = new Customer();
        customer.setName("字母歌");

        Order order1 = new Order();
        order1.setName("檯球杆");

        Order order2 = new Order();
        order2.setName("檯球桌");


//		// 客戶關聯訂單
        customer.getOrders().add(order1);
        customer.getOrders().add(order2);

//		// 訂單關聯客戶(inverse無效)
//		order1.setCustomer(customer);
//		order2.setCustomer(customer);

        //保存訂單,因爲設置cascade級聯添加,在添加客戶時自動添加關聯的訂單
//		session.save(order1);
//		session.save(order2);

        //3 保存客戶
        session.save(customer);

        session.getTransaction().commit();
        session.close();
    }

    /**
     * 刪除客戶
     * 	inverse=true:刪除時有外鍵數據報錯
     *  inverse=false:刪除時有外鍵,外鍵設置爲null
     *  cascade:delete:當刪除客戶時,訂單同時刪除。。。
     */
    @Test
    public void testDeleteCustomer(){
        //創建客戶,並保存客戶--成功
        Session session = HibernateUtils.openSession();
        session.beginTransaction();

        //必須讓客戶的訂單集合有訂單,才能級聯
        Customer c = (Customer) session.get(Customer.class, 8);

        session.delete(c);

        session.getTransaction().commit();
        session.close();
    }
}

九、inverse 、cascade

1、inverse 屬性

概述: 設置關聯關係的方向,當前類是否維護關聯關係,是否維護外鍵的值,只配置在set一方(一的一方配置)
在這裏插入圖片描述
保存客戶和訂單:讓客戶(一)維護關聯關係

  • inverse=false:因爲維護關聯關係, 添加客戶時,執行update語句關聯外鍵=客戶的主鍵
  • inverse=true::因爲不維護關聯關係,添加客戶時,外鍵=null

2、cascade級聯操作

概述: 一方操作,級聯另外一方做相同的操作
在這裏插入圖片描述
cascade=save-update:級聯添加和修改,客戶添加,自動客戶管理的訂單

十、關聯關係映射——多對多映射

模擬學生與課程(Student -> Course):(多 :多)
一個學生 -> 多門課程
一門課程 -> 多個學生
在這裏插入圖片描述

第一步:新建 Student.java 、Course.java 實體類
package cn.lemon.f_manytomany.domain;

import java.util.HashSet;
import java.util.Set;

public class Student {
    private Integer id;
    private String name;

    private Set<Course> courses = new HashSet<>();

    public Student() {
    }

    public Student(String name) {//構造函數傳值
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Course> getCourses() {
        return courses;
    }

    public void setCourses(Set<Course> courses) {
        this.courses = courses;
    }
}
package cn.lemon.f_manytomany.domain;

import java.util.HashSet;
import java.util.Set;

public class Course {
    private Integer id;
    private String name;

    private Set<Student> students = new HashSet<>();

    public Course() {
    }

    public Course(String name) {//構造函數傳值
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}
第二步:新建 Student.hbm.xml 、Course.hbm.xml 映射文件
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<!--Student 的 Hibernate 映射文件-->
<hibernate-mapping>
    <class name="cn.lemon.f_manytomany.domain.Student" table="student">
        <id name="id" type="java.lang.Integer">
            <column name="id_"/>
            <generator class="native"/>
        </id>
        <property name="name" type="java.lang.String">
            <column name="name_"/>
        </property>

        <!--
        	映射多對多
        		* name:關聯屬性名
        		* table:中間表名
        		* inverse:
        			false:當前類維護關聯關係(中間表的外鍵)
        			true:當前類不維護關聯關係(中間表的外鍵)
        		* key -> column:當前表在中間表的外鍵
        		* many-to-many:映射多對多
        			* class:另一方類路徑
        			* column:對方表在中間表的外鍵
        -->
        <set name="courses" table="student_course_" inverse="false">
            <key>
                <column name="student_id_" />
            </key>
            <many-to-many column="course_id_" class="cn.lemon.f_manytomany.domain.Course"/>
        </set>
    </class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--Course 的 Hibernate 映射文件-->
<hibernate-mapping>
    <class name="cn.lemon.f_manytomany.domain.Course" table="course">
        <id name="id" type="java.lang.Integer">
            <column name="id_"/>
            <generator class="native"/>
        </id>
        <property name="name" type="java.lang.String">
            <column name="name_"/>
        </property>

        <!--
        	映射多對多
        		* name:關聯屬性名
        		* table:中間表名
        		* inverse:
        			false:當前類維護關聯關係(中間表的外鍵)
        			true:當前類不維護關聯關係(中間表的外鍵)
        		* key -> column:當前表在中間表的外鍵
        		* many-to-many:映射多對多
        			* class:另一方類路徑
        			* column:對方表在中間表的外鍵
        -->
        <set name="students" table="student_course_" inverse="true">
            <key>
                <column name="course_id_" />
            </key>
            <many-to-many column="student_id_" class="cn.lemon.f_manytomany.domain.Student"/>
        </set>
    </class>
</hibernate-mapping>
第三步:測試
package cn.lemon.f_manytomany.test;

import cn.lemon.f_manytomany.domain.Course;
import cn.lemon.f_manytomany.domain.Student;
import cn.lemon.utils.HibernateUtils;
import org.hibernate.Session;
import org.junit.Test;

public class ManytomanyTest {
    @Test
    public void testCreateTable() {
        HibernateUtils.getCurrentSession();
    }

    /**
     * 加載
     */
    @Test
    public void test2() {
        Session session = HibernateUtils.openSession();
        Student zhangsan = (Student) session.get(Student.class,1);
        System.out.println(zhangsan.getName());

        System.out.println("-------------------------");
        for (Course c : zhangsan.getCourses()) {
            System.out.println(c.getName());
        }
        System.out.println("*************************");

        Course php = (Course) session.get(Course.class, 2);
        System.out.println(php.getName());
        System.out.println("-------------------------");
        for (Student s : php.getStudents()) {
            System.out.println(s.getName());
        }
        System.out.println("*************************");
        session.close();
    }

    /**
     * 添加
     */
    @Test
    public void test3() {
        Session session = HibernateUtils.getCurrentSession();
        session.beginTransaction();

        Student zhangsan = new Student("張三");
        Student lisi = new Student("李四");
        Student wangwu = new Student("王五");
        Student zhaoer = new Student("趙二");

        Course java = new Course("java");
        Course c = new Course("c#");
        Course php = new Course("php");
        Course hadoop = new Course("hadoop");

        //因爲學員的inverse=false,所以學員可以維護關聯關係(中間的外鍵)
        zhangsan.getCourses().add(java);
        zhangsan.getCourses().add(c);
        zhangsan.getCourses().add(hadoop);

        lisi.getCourses().add(c);
        lisi.getCourses().add(php);

        wangwu.getCourses().add(php);
        wangwu.getCourses().add(hadoop);

        zhaoer.getCourses().add(java);
        zhaoer.getCourses().add(php);

        //cascade=save-update
        session.save(java);
        session.save(c);
        session.save(php);
        session.save(hadoop);

        session.save(zhangsan);
        session.save(lisi);
        session.save(wangwu);
        session.save(zhaoer);

        session.getTransaction().commit();
    }
}

十一、關聯關係映射——一對一映射(唯一索引外鍵)

在這裏插入圖片描述

第一步:新建 Person.java 、SheBao.java 實體類
package cn.lemon.g_onetoone_1.domain;

public class Person {
    private Integer id;
    private String name;

    private SheBao sheBao;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public SheBao getSheBao() {
        return sheBao;
    }

    public void setSheBao(SheBao sheBao) {
        this.sheBao = sheBao;
    }
}
package cn.lemon.g_onetoone_1.domain;

public class SheBao {
    private Integer id;
    private String name;

    private Person person;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }
}
第二步:新建 Person.hbm.xml 、SheBao.hbm.xml 映射文件
<!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="cn.lemon.g_onetoone_1.domain.Person" table="person">
        <id name="id" type="java.lang.Integer">
            <column name="id_"/>
            <generator class="native"/>
        </id>
        <property name="name" type="java.lang.String">
            <column name="name_"/>
        </property>
        <!-- 主鍵表
            property-ref:指定對方關聯屬性名,引用外鍵
        -->
        <one-to-one name="sheBao" class="cn.lemon.g_onetoone_1.domain.SheBao" property-ref="person"></one-to-one>
    </class>
</hibernate-mapping>
<!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="cn.lemon.g_onetoone_1.domain.SheBao" table="shebao">
        <id name="id" type="java.lang.Integer">
            <column name="id_"/>
            <generator class="native"/>
        </id>
        <property name="name" type="java.lang.String">
            <column name="name_"/>
        </property>
        <!-- 外檢表
            unique:唯一索引
            column:外鍵
        -->
        <many-to-one name="person" column="person_id_" unique="true"></many-to-one>
    </class>
</hibernate-mapping>
第三步:測試
package cn.lemon.g_onetoone_1.test;

import cn.lemon.d_refactor.dao.BaseDao;
import cn.lemon.g_onetoone_1.domain.Person;
import cn.lemon.g_onetoone_1.domain.SheBao;
import cn.lemon.utils.HibernateUtils;
import org.junit.Test;

public class OnetooneTest {
    @Test
    public void testCreateDb() {
        HibernateUtils.getCurrentSession();
    }
    
    /**
     * 添加
     */
    @Test
    public void test2() {
        Person u1 = new Person();
        u1.setName("張三");
        Person u2 = new Person();
        u2.setName("李四");

        SheBao s1 = new SheBao();
        s1.setName("社保1");
        SheBao s2 = new SheBao();
        s2.setName("社保2");

        s1.setPerson(u1);
        s2.setPerson(u1); //因爲張三有2個社保違反唯一約束,所以報錯。。。

        BaseDao dao = new BaseDao();

        dao.add(u1);
        dao.add(u2);

        dao.add(s1);
        dao.add(s2);
    }
}

十二、關聯關係映射——一對一映射(使用主鍵做外鍵)

在這裏插入圖片描述

第一步:新建 Driver.java 、JiaZhao.java 實體類
package cn.lemon.g_onetoone_2.domain;

public class Driver {
	
	private Integer id;
	private String name;

	private JiaZhao jiaZhao;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public JiaZhao getJiaZhao() {
		return jiaZhao;
	}

	public void setJiaZhao(JiaZhao jiaZhao) {
		this.jiaZhao = jiaZhao;
	}
}
package cn.lemon.g_onetoone_2.domain;

public class JiaZhao {
	
	private Integer id;
	private String name;

	private Driver driver;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Driver getDriver() {
		return driver;
	}

	public void setDriver(Driver driver) {
		this.driver = driver;
	}
}
第二步:新建 Driver.hbm.xml 、JiaZhao.hbm.xml 映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-11-8 11:20:35 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="cn.lemon.g_onetoone_2.domain.Driver" table="driver">
        <id name="id" type="integer">
            <column name="id_" />
            <generator class="native" />
        </id>
        <property name="name" type="string">
            <column name="name_" />
        </property>

        <!-- 主鍵表 -->
        <one-to-one name="jiaZhao" class="cn.lemon.g_onetoone_2.domain.JiaZhao"></one-to-one>
    </class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-11-8 11:20:35 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="cn.lemon.g_onetoone_2.domain.JiaZhao" table="jiazhao">
        <id name="id" type="integer">
            <column name="id_" />
            <!--
                foreign:引用駕駛員的主鍵作爲自己的主鍵
            -->
            <generator class="foreign" >
                <param name="property">driver</param>
            </generator>
        </id>
        <property name="name" type="string">
            <column name="name_" />
        </property>

        <!-- 外鍵表
            constrained:表示在添加修改時不處理這個屬性
        -->
        <one-to-one name="driver" class="cn.lemon.g_onetoone_2.domain.Driver" constrained="true"/>
    </class>
</hibernate-mapping>
第三步:測試
package cn.lemon.g_onetoone_2.test;

import cn.lemon.d_refactor.dao.BaseDao;
import cn.lemon.g_onetoone_2.domain.Driver;
import cn.lemon.g_onetoone_2.domain.JiaZhao;
import cn.lemon.utils.HibernateUtils;
import org.junit.Test;

public class One2OneTest {

	@Test
	public void testCreateDb() {
		HibernateUtils.getCurrentSession();
	}
	
	/**
	 * 添加
	 */
	@Test
	public void test2() {
		Driver u1 = new Driver();
		u1.setName("張三");
		Driver u2 = new Driver();
		u2.setName("李四");
		
		JiaZhao s1 = new JiaZhao();
		s1.setName("駕照1");
		JiaZhao s2 = new JiaZhao();
		s2.setName("駕照2");
		
		s1.setDriver(u1);
		s2.setDriver(u1); //因爲張三有2個社保違反唯一約束,所以報錯。。。

		BaseDao dao = new BaseDao();
		
		dao.add(u1);
		dao.add(u2);
		
		dao.add(s1);
		dao.add(s2);		
	}
}

十二、抓取策略(瞭解)

1、檢索方式
  • 立即檢索:立即查詢,在執行查詢語句時,立即查詢所有的數據。
  • 延遲檢索:延遲查詢,在執行查詢語句之後,在需要時在查詢。(延遲加載)
2、檢查策略
  • 類級別檢索:當前的類的屬性獲取是否需要延遲。
  • 關聯級別的檢索:當前類 關聯 另一個類是否需要延遲。
3、類級別檢索
  • get:立即檢索。get方法一執行,立即查詢所有字段的數據。
  • load:使用延遲檢索測試。默認情況,load方法執行後,如果只使用OID的值不進行查詢,如果要使用其他屬性值將查詢 。
Customer.hbm.xml  
<class  lazy="true | false">
		lazy 默認值true,表示延遲檢索,默認,使用關聯數據時才檢索關聯表
		設置false, 表示load使用立即檢索。查詢時立即檢索關聯數據

測試代碼

package cn.lemon.h_lazy.test;

import cn.lemon.h_lazy.domain.Customer;
import cn.lemon.utils.HibernateUtils;
import org.hibernate.Session;
import org.junit.Test;

public class ClassLazyTest {
	
	/**
	 * get方法:使用立即檢索,在不打印客戶信息的情況下,也會加載數據
	 */
	@Test
	public void test1() {
		Session session = HibernateUtils.openSession();
		Customer c = (Customer) session.get(Customer.class, 3);
		session.close();
	}
	
	/**
	 * load方法:使用立即檢索
	 */
	@Test
	public void test2() {
		Session session = HibernateUtils.openSession();
		Customer c = (Customer) session.load(Customer.class, 3);
		
		session.close();//當懶加載session關閉,拋出org.hibernate.LazyInitializationException: could not initialize proxy [cn.lemon.h_lazy.domain.Customer#3] - no Session
		System.out.println("---------------------------");
		System.out.println(c.getName()); //使用其他屬性是才檢索數據庫數據,延遲檢索
	}
}
4、關聯級別檢索—— 一對多
  • 容器 <set> 提供兩個屬性:fetch、lazy
    • fetch:確定使用sql格式
    • lazy:關聯對象是否延遲。
  • fetch:數據抓取策略join、select、subselect
  • select:使用多個select語句(默認值)先查詢客戶,然後根據lazy檢索策略查詢訂單
  • subselect:使用子查詢,查詢多行客戶是,使用自查詢查詢訂單數據
    select … from order_ where custer_id in (select… from customer ..)
5、關聯級別檢索—— 多對一
  • <many-to-one fetch="" lazy=""> (<one-to-one>)
  • fetch取值:join、select
    join:底層使用迫切左外連接
    select:多條select語句
  • lazy取值:false、proxy、no-proxy
    false:立即
    proxy:採用關聯對象 類級別檢索的策略。
    訂單 關聯 客戶 (多對一)
    訂單 立即獲得 客戶,需要在客戶Customer.hbm.xml <class lazy="false">
    訂單 延遲獲得 客戶,需要在客戶Customer.hbm.xml <class lazy="true">
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章