Hibernate配置文件和常用方法函數(shù)詳解(二)

配置映射文件和數(shù)據(jù)庫(kù)的關(guān)系
<property name="hibernate.hbm2ddl.auto">update</property>
  • update:如果數(shù)據(jù)庫(kù)沒有創(chuàng)建表,自動(dòng)創(chuàng)建表
  • create:每次啟動(dòng)hibernate都會(huì)創(chuàng)建表
  • create-drop:每次啟動(dòng)hibernate都會(huì)創(chuàng)建表,并執(zhí)行完后刪除表
  • validate :檢查hbm的文件,如果和數(shù)據(jù)庫(kù)的字段不一致會(huì)拋異常
數(shù)據(jù)庫(kù)方言
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>

*hbm.xml映射文件解說

實(shí)體類entity(model)的編寫規(guī)則
  • 我們?cè)谑褂肏ibernate時(shí),書寫User類,這個(gè)類我們稱為JavaBean
  • JavaBean可以理解為可以提供私有屬性,并提供get和set方法
  • POJO(Plain Ordinary Java Object)其實(shí)就是一個(gè)普通的JavaBean
  • 實(shí)體類也被稱為模型,在Hibernate中,也稱為實(shí)體類,是與數(shù)據(jù)庫(kù)表直接關(guān)聯(lián)的
編寫規(guī)則如下
  • 提供一個(gè)無參public控制符的構(gòu)造方法
  • 提供一個(gè)標(biāo)識(shí)(屬性、映射數(shù)據(jù)表主鍵字段,提供id)
  • 所有屬性提供public訪問控制符的get和set方法
  • 標(biāo)識(shí)屬性應(yīng)盡量使用基本類型的包裝類
  • 不要使用final修飾實(shí)體(將無法生成代理對(duì)象進(jìn)行優(yōu)化)
持久化對(duì)象的唯一標(biāo)識(shí)OID
  • Java按地址區(qū)分同一個(gè)類的不同對(duì)象
  • 關(guān)系數(shù)據(jù)庫(kù)使用主鍵區(qū)分同一條記錄
  • Hibernate使用OID來建立內(nèi)存中的對(duì)象和數(shù)據(jù)庫(kù)記錄的對(duì)應(yīng)關(guān)系(結(jié)論:對(duì)象的OID和數(shù)據(jù)庫(kù)的表的主鍵對(duì)應(yīng))
  • 保證OID的唯一性,應(yīng)該讓Hibernate來為OID進(jìn)行賦值
區(qū)分自然主鍵和代理主鍵
  • 主鍵需要具備不為空/不能重復(fù)/不能被修改
  • 自然主鍵:在業(yè)務(wù)中,某個(gè)屬性符合主鍵的三個(gè)要求,該屬性可以作為主鍵列(登錄名可以是自然主鍵)
  • 代理主鍵:在業(yè)務(wù)中,不存在符合以上三個(gè)條件的屬性,那么就增加一個(gè)沒有意義的列作為主鍵
基本數(shù)據(jù)類型和包裝類型
  • 基本數(shù)據(jù)類型和包裝類型對(duì)應(yīng)hibernate的映射類型相同
  • 基本類型無法表達(dá)null,數(shù)字類型的默認(rèn)值是0
  • 包裝類默認(rèn)值為null,當(dāng)對(duì)于默認(rèn)值由業(yè)務(wù)意義的時(shí)候需要使用包裝類型
SQL、Hibernate和對(duì)象類型對(duì)應(yīng)表
image.png
主鍵的生成策略【非常重要】

1、id主鍵,如果屬性與表字段不一樣需要指定column
2、column屬性對(duì)應(yīng)表的列名
3、type數(shù)據(jù)類型
主鍵生成策略 常用2、5、6、7
1、increment由hibernate自己維護(hù)自動(dòng)增加,原理使用max函數(shù),然后+1,不建議使用,因?yàn)橛芯€程安全問題
2、identity:hibernate使用數(shù)據(jù)庫(kù)自帶的自動(dòng)增長(zhǎng)方式
例如:mysql是auto_increment
3、squence:hibernate使用采用數(shù)據(jù)庫(kù)系統(tǒng)
例如:oracle提供的系統(tǒng)
4、hilo:hibernate自己實(shí)現(xiàn)的算法,自己生成主鍵(hilo算法)幾乎不用
5、native根據(jù)數(shù)據(jù)庫(kù)自動(dòng)選擇identity、squnce、hilo
6、uuid采用字符串唯一值
7、assigned自然主鍵,由程序自動(dòng)維護(hù)

具體代碼如下:
<!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.gfy.hibernate.domain.User" table="t_user">
        <!--1、id主鍵,如果屬性與表字段不一樣需要指定column
          2、column屬性對(duì)應(yīng)表的列名
          3、type數(shù)據(jù)類型-->
        <id name="uid" column="id">
            <!--主鍵生成策略 常用2、5、6、7
            1、increment由hibernate自己維護(hù)自動(dòng)增加,原理使用max函數(shù),然后+1,不建議使用,因?yàn)橛芯€程安全問題
            2、identity:hibernate使用數(shù)據(jù)庫(kù)自帶的自動(dòng)增長(zhǎng)方式
            例如:mysql是auto_increment
            3、squence:hibernate使用采用數(shù)據(jù)庫(kù)系統(tǒng)
            例如:oracle提供的系統(tǒng)
            4、hilo:hibernate自己實(shí)現(xiàn)的算法,自己生成主鍵(hilo算法)幾乎不用
            5、native根據(jù)數(shù)據(jù)庫(kù)自動(dòng)選擇identitysqunce、hilo中的幾乎不用
            6、uuid采用字符串唯一值
            7、assigned自然主鍵,由程序自動(dòng)維護(hù)-->
            <generator class="native"></generator>
        </id>
        <property name="username"></property>
        <property name="password"></property>
        <property name="gender"></property>
    </class>
</hibernate-mapping>
普通屬性

class標(biāo)簽的dynamic-insert=“true”,是否動(dòng)態(tài)生成插入語句【如果屬性字段為空,就不會(huì)有這些字段的插入語句】

<class name="com.gfy.hibernate.domain.User" table="t_user" dynamic-insert="true">

class標(biāo)簽的dynamic-update=“true”與insert類似

type的使用和設(shè)置,如圖:
image.png
Date類型
  • property中type不寫,數(shù)據(jù)庫(kù)對(duì)應(yīng)的類型,datetime【年,月,日,時(shí),分,秒】
  • type中date數(shù)據(jù)庫(kù)對(duì)應(yīng)的類型,date【年、月、日】
  • type中time,數(shù)據(jù)庫(kù)對(duì)應(yīng)的類型time【時(shí)、分、秒】
  • type中timestamp,數(shù)據(jù)庫(kù)對(duì)應(yīng)的類型timestamp【時(shí)間戳】不太好用,如果需要時(shí)間戳,建議使用long類型

Hibernate實(shí)體的狀態(tài)

狀態(tài)介紹
  • 實(shí)體Entity有三種狀態(tài),瞬時(shí)狀態(tài)、持久狀態(tài)、脫管狀態(tài)
  • 瞬時(shí)狀態(tài) transient、session沒有緩存,數(shù)據(jù)庫(kù)也沒有記錄,oid沒有值
  • 持久狀態(tài),persistent、session有緩存,數(shù)據(jù)庫(kù)有記錄,oid有值
  • 脫管狀態(tài) datached session沒有緩存,數(shù)據(jù)庫(kù)有記錄,oid有值
    瞬時(shí)轉(zhuǎn)換持久:新創(chuàng)建一個(gè)對(duì)象,經(jīng)過save或者saveOrUpdate調(diào)用后,會(huì)變成持久狀態(tài)
    總結(jié)狀態(tài)轉(zhuǎn)換過程:查詢操作get、load、createQuery、createCriteria等獲的都是持久狀態(tài),瞬時(shí)狀態(tài)調(diào)用save、update之后變成持久狀態(tài)
    持久狀態(tài)轉(zhuǎn)換脫管狀態(tài):session.clear()清除所有、session.close()關(guān)閉、session.evict(obj)清除指定的PO對(duì)象
一級(jí)緩存概念

一級(jí)緩存又稱為session級(jí)別的緩存,當(dāng)獲得一次會(huì)話(session)、hibernate在session中創(chuàng)建多個(gè)集合(map)用于存放操作數(shù)據(jù)(PO對(duì)象)為程序,優(yōu)化服務(wù),如果之后需要相應(yīng)的數(shù)據(jù),hibernate優(yōu)先從session中緩存中獲取,如果有就使用,如果沒有在查詢數(shù)據(jù)庫(kù),當(dāng)session關(guān)閉時(shí),一級(jí)緩存銷毀

User user = (User) session.get(User.class,1);
        System.out.println(user);
        User user1 = (User) session.get(User.class,1);
        System.out.println(user1);
移除緩存
   //方法一
    session.clear();
    //方法二
    session.evict(user)
一級(jí)緩存快照【掌握】

快照與一級(jí)緩存一樣的存放位置,對(duì)一級(jí)緩存數(shù)據(jù)進(jìn)行備份,保證數(shù)據(jù)庫(kù)的數(shù)據(jù)與一級(jí)緩存的數(shù)據(jù)必須一致,如果一級(jí)緩存修改了,在執(zhí)行commit提交時(shí),將自己刷新為一級(jí)緩存,執(zhí)行update語句,將一級(jí)緩存的數(shù)據(jù)與更新到數(shù)據(jù)庫(kù)


image.png
Session session = HibernateUtils.openSession();
        session.beginTransaction().begin();
        User user = (User) session.get(User.class,1);
        user.setUsername("lisi02");
        session.beginTransaction().commit();
        session.close();
session.flush()手動(dòng)刷新、保持一致緩存與數(shù)據(jù)庫(kù)一致

此時(shí)會(huì)執(zhí)行兩條update語句,如果去除flush代碼只有一條update語句

一級(jí)緩存細(xì)節(jié)

HQL的結(jié)果或會(huì)進(jìn)入一級(jí)緩存,控制臺(tái)查看只有一次查詢語句
        List list = session.createQuery("from User").list();
        User user = (User) session.get(User.class,1);
        System.out.println(user);
SQL不會(huì)對(duì)數(shù)據(jù)進(jìn)行session緩存,控制臺(tái)查看有兩條查詢語句
        SQLQuery query = session.createSQLQuery("select * from t_user");
        System.out.println(query.list());
        User user = (User) session.get(User.class,1);
        System.out.println(user);
Criteria 對(duì)數(shù)據(jù)進(jìn)行一級(jí)緩存,控制臺(tái)查看只有一次查詢語句
        Criteria criteria = session.createCriteria(User.class);
        System.out.println(criteria.list());
        User user = (User) session.get(User.class,1);
        System.out.println(user);
其他API

save和persist方法的區(qū)別
save方法:瞬狀態(tài)轉(zhuǎn)換持久態(tài),會(huì)初始化OID
1、執(zhí)行save方法,立即觸發(fā)insert語句,從數(shù)據(jù)庫(kù)獲得的主鍵的值OID
2、執(zhí)行save之前,設(shè)置OID將忽略
3、如果執(zhí)行查詢session緩存移除時(shí),在執(zhí)行save方法,將執(zhí)行insert

    User user = new User();
    user.setUid(2);
    user.setUsername("April");
    user.setPassword("123456");
    user.setGender("female");
    session.save(user);
image.png

image.png

在執(zhí)行save方法,立即觸發(fā)insert語句,從數(shù)據(jù)庫(kù)中獲取主鍵的值

persist方法:瞬時(shí)狀態(tài)轉(zhuǎn)換持久態(tài)
  • 在保存對(duì)象之前,不能設(shè)置id,否則會(huì)報(bào)錯(cuò)
  • save和persist都是持久化對(duì)象的作用
  • save因?yàn)樾枰祷匾粋€(gè)主鍵,因此會(huì)立即執(zhí)行insert語句,而Persist在事務(wù)外部,調(diào)用時(shí)則不會(huì)立即執(zhí)行insert語句,在事務(wù)內(nèi)調(diào)用還會(huì)立即執(zhí)行insert語句
Hibernate的多表關(guān)聯(lián)關(guān)系映射
image.png

一對(duì)多:一表(主表)必須有主鍵,多表(從表)必須外鍵,主表主鍵與從表外鍵,形成主外鍵關(guān)系
一對(duì)一:主外鍵關(guān)系

案例:顧客與訂單的關(guān)系

分析:一個(gè)顧客有多個(gè)訂單,一個(gè)訂單只能有一個(gè)顧客,因此這種關(guān)系是一對(duì)多的關(guān)系,顧客是主表
顧客類

public class Customer {
    private Integer id;
    private String name;
    private Set<Order> orders = new HashSet<Order>();

    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;
    }
}

訂單類

public class Order {
    private Integer id;
    private String orderNo;
    private Customer customer;

    public Integer getId() {
        return id;
    }

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

    public String getOrderNo() {
        return orderNo;
    }

    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}

Customer.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 package="com.gfy.hibernate.domain">
    <class name="Customer" table="t_customer">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <set name="orders">
            <key column="customer_id"></key>
            <one-to-many class="Order"></one-to-many>
        </set>
    </class>
</hibernate-mapping>

Order.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 package="com.gfy.hibernate.domain">
    <class name="Order" table="t_order">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="orderNo"></property>
        <many-to-one name="customer" column="customer_id"></many-to-one>
    </class>
</hibernate-mapping>

具體執(zhí)行的代碼如下:

        Session session = HibernateUtils.openSession();
        session.beginTransaction().begin();
        Customer customer = new Customer();
        customer.setName("April");
        Order order = new Order();
        order.setCustomer(customer);
        order.setOrderNo("JD"+Math.random()*10000);
        order.setName("lipstick");

        Order order1 = new Order();
        order1.setCustomer(customer);
        order1.setOrderNo("TB"+Math.random()*10000);
        order1.setName("eyebrow pencil");

        Set<Order> orders = new HashSet<>();
        orders.add(order);
        orders.add(order1);
        customer.setOrders(orders);
        //因?yàn)橛唵我蕾囍麈I的id 所以這里需要先保存顧客
        session.save(customer);
        session.save(order);
        session.save(order1);
        session.beginTransaction().commit();
        session.close();
數(shù)據(jù)庫(kù)查詢結(jié)果
image.png

image.png

那么問題來了,為啥我們?cè)趫?zhí)行上面的代碼的時(shí)候查詢數(shù)據(jù)庫(kù)在沒有創(chuàng)建顧客和訂單表的情況下能夠查詢到這兩張表的數(shù)據(jù)呢,表是如何創(chuàng)建和插入數(shù)據(jù)的,其實(shí)我們?cè)谖恼麻_頭都已經(jīng)講過了,配置文件配置如下就可以了

<property name="hibernate.hbm2ddl.auto">update</property>

當(dāng)然我們還需要把JavaBean實(shí)體類的映射屬性和數(shù)據(jù)庫(kù)表的屬性進(jìn)行關(guān)聯(lián)

<mapping resource="com/gfy/hibernate/domain/Customer.hbm.xml"/>
        <mapping resource="com/gfy/hibernate/domain/Order.hbm.xml"/>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容