Hibernate的casecade與inverse探究

Hibernate級聯問題

1.級聯是指兩個對象之間的操做聯動關係,對一個對象執行了操做以後,對其指定的級聯對象也須要執行相同的操做; html

2.級聯配置經過many-to-onecascade屬性實現; sql

3.cascade屬性有四種取值:
  all
:全部操做都執行級聯操做;
  none
:全部操做都不執行級聯操做;
  save-update
:保存和更新時執行級聯操做;
  delete
:刪除時執行級聯操做; 數據庫

4.經過級聯操做能夠解決持久化對象不能直接引用瞬時對象的問題。session

 

Hibernateinverse屬性與cascade屬性

   Hibernate集合映射中,常常會使用到"inverse""cascade"這兩個屬性。對於我這樣,Hibernate接觸不深和語文水平夠 爛的種種因素,發現這兩個屬性實在是難以理解,無奈只好將這個兩個屬性解釋工做交給了GoogleBaidu,查看了許多牛人的解釋,加上本身在 Eclipse上的調試,對"inverse""cascade"這兩個屬性有了必定的看法。app

 

"inverse"屬性探究 性能

  "inverse"-直譯過來就是"反轉,使顛倒"的意思,書面化的解釋爲"是否將關係維護的權力交給對方"(這個解釋真夠蛋疼的-_-!!,就是理解不了)。 Hibernate中的"inverse"屬性只有兩個值"true""false""true"表示將關係維護的權力交給對方,"false"表示不交出維護權力(默認值)。 測試

  例若有兩張表,customerorders,他們的關係是一對多,customer是一方,orders爲多方。ui

drop table if exists customer
drop table if exists orders


create table customer
(
    id varchar(255) not null,
    username varchar(255),
    password varchar(255),
    age integer,
    register_time datetime,
    primary key (id)
)


create table orders
(
    id varchar(255) not null,
    orderNumber varchar(255),
    balance integer,
    customer_id varchar(255),
    primary key (id)
)
spa

  兩表對應的hbm文件,對應的POJO類:hibernate

/*customer表對應的POJO*/
public class Customer
{
    private String id;
    private String username;
    private String password;
    private Timestamp registerTime;
    private int age;
    private Set<Order> orders = new HashSet<Order>();

    public Customer()
    {

    }

    /*get and set method*/

}

/*orders
表對應的POJO*/
public class Order
{
    private String id;
    private String orderNumber;
    private int balance;
    private Customer customer;
   
    public Order()
    {
       
    }

    /* get and set method*/
}

 

<!--Customer類的hbm文件-->
    <hibernate-mapping>
        <class name="com.suxiaolei.hibernate.pojos.Customer" table="customer">
            <id name="id" type="string">
                <column name="id"></column>
                <generator class="uuid"></generator>
            </id>
            
            <property name="username" column="username" type="string"></property>
            <property name="password" column="password" type="string"></property>
            <property name="age" column="age" type="integer"></property>
            <property name="registerTime" column="register_time" type="timestamp"></property>
           
            <set name="orders" inverse="true" cascade="all">
                <key column="customer_id" ></key>
                <one-to-many class="com.suxiaolei.hibernate.pojos.Order"/>
            </set>
       
        </class>
    </hibernate-mapping>

<!--Order
類的hbm文件-->
    <hibernate-mapping>
        <class name="com.suxiaolei.hibernate.pojos.Order" table="orders">
            <id name="id" type="string">
                <column name="id"></column>
                <generator class="uuid"></generator>
            </id>
           
            <property name="orderNumber" column="orderNumber" type="string"></property>
            <property name="balance" column="balance" type="integer"></property>
           
            <many-to-one name="customer" class="com.suxiaolei.hibernate.pojos.Customer">
                <column name="customer_id"></column>
            </many-to-one>       
        </class>
    </hibernate-mapping>

下面寫一些測試代碼測試"inverse"屬性的特性:

狀況一:將"inverse"設置爲true,讓多方維護關係

        try
        {
            tx = session.beginTransaction();
           
            /*
             *
建立Customer對象,並設置其屬性值
             */
            Customer customer = new Customer();
           customer.setUsername("zhangsan");
           customer.setPassword("123456");
            customer.setAge(22);
            customer.setRegisterTime(new Timestamp(new Date().getTime()));
           
            /*
             *
建立Order對象order1,並設置其屬性值
             */
            Order order1 = new Order();
           order1.setOrderNumber("a1a2a3");
            order1.setBalance(1000);
            order1.setCustomer(customer);//
customer對象關聯到order1對象上
           
            /*
             *
建立Order對象order2,並設置其屬性值
             */
            Order order2 = new Order();
           order2.setOrderNumber("d3d2d1");
            order2.setBalance(670);
            order2.setCustomer(customer);///
customer對象關聯到order2對象上
           
           customer.getOrders().add(order1);//
order1對象關聯到customer對象上
           customer.getOrders().add(order2);//
order2對象關聯到customer對象上
           
           session.saveOrUpdate(customer);
           
            tx.commit();
        }
        catch (Exception e)
        {
            if(tx != null)
            {
                tx.rollback();
            }
           
            e.printStackTrace();
        }
        finally
        {
            session.close();
        }

數據庫中的數據更新爲:

customer表: 

說明: http://pic002.cnblogs.com/images/2012/369936/2012011715074772.png

orders表:

說明: http://pic002.cnblogs.com/images/2012/369936/2012011715090557.png

如今將order1.setCustomer(customer);這段代碼註釋掉,再次運行程序:

customer表:

說明: http://pic002.cnblogs.com/images/2012/369936/2012011715125440.png

orders表:

說明: http://pic002.cnblogs.com/images/2012/369936/2012011715133685.png

   能夠到看到顯著地差異了,第一次保存"id"="402881e534ea7c750134ea7c76bc0001"的數據時,orders表中插入 了兩條數據,他們的customer_id都爲customer中對應記錄的主鍵值,而第二次保存記 "id"="402881e534ea81be0134ea81bfea0001"的數據時,因爲先前將原來的代碼段order1.setCustomer(customer);註釋掉了,此時order表中插入的數據中order1表明的那條記錄沒有customer_id值。

   從以上現象能夠有助於理解"inverse"這個屬性。首先,"inverse"控制關係維護權力,那麼什麼是"關係"?,關係的具體體現是什麼?在以 上例子中,"關係"就是兩個表之間的關係,一般爲"一對多","一對一","多對多"三種關係,而關係的具體體現爲orders表中的 customer_id列,而"inverse"屬性就是告訴Hibernate哪一方有權力管理和維護這一列。上面的例子將"inverse"設置爲 true那麼customer_id這一列由多方(order對象)維護。這說明了,只有order對象對關係的操做會反映到數據庫中。(對象對關係的操 做就是對關聯屬性的操做,例如order對象對自身的"customer"屬性操做,customer對象對自身的orders集合 Set<Order>)操做)

  例如,將id="402881e534ea7c750134ea7c76bc0001"customer對象從數據庫中取出,獲取到該customer對象所關聯的order對象集合,將該customer對象所關聯的order對象刪除。

Customer customer = (Customer)session.get(Customer.class, "402881e534ea7c750134ea7c76bc0001");
Order order = (Order)session.get(Order.class, "402881e534ea7c750134ea7c76ce0002");
           
System.out.println("customer association order count:"+customer.getOrders().size());
customer.getOrders().remove(order);
System.out.println("customer association order count:"+customer.getOrders().size());
           
session.saveOrUpdate(customer);

//Console Output:

customer association order count:2
customer association order count:1

  能夠看到customer中關聯的order對象集合確實有對象被刪除了,若操做有效,表示該order對象與customer對象沒有關係了,反映到數據庫中應該將該order對象對應的customer_id設置爲null。如今查看一下數據庫數據:

說明: http://pic002.cnblogs.com/images/2012/369936/2012011715424979.png

看到了吧,剛剛那個操做就是個無用操做,不會反應到數據庫中。咱們修改一下程序代碼:

Customer customer = (Customer)session.get(Customer.class, "402881e534ea7c750134ea7c76bc0001");
Order order = (Order)session.get(Order.class, "402881e534ea7c750134ea7c76ce0002");
           
order.setCustomer(null);
           
session.saveOrUpdate(customer);

  此次咱們使用order對象來操做關係,將該order對象與customer對象脫離關係,若操做有效,則反映在數據庫中應該是該order對象的customer_id字段的值變成null,如今查看一下數據庫:

說明: http://pic002.cnblogs.com/images/2012/369936/2012011715523861.png

能夠看到,這次操做成功的反映到了數據庫中了。
 

況2、將"inverse"屬性設置爲"false",雙方都維護關係(由於沒有一方交出權力,"inverse"的默認值爲"false",而 "inverse"屬性只能在setlistmap等幾個標籤中設置,像many-to-one這一類的標籤都不能設置"inverse"這個屬性 值,它們只能取值"false"

  這裏會產生書中所說的性能問題(囧,這個也是理解了好久好久),這個無論怎麼說你均可能理解不了,我就是這樣的(-_-!!),因此我建議使用第三方的軟件將Hibernate輸出的SQL語句的綁定值顯示出來(能夠參考這裏)。 之因此會產生性能爲題,當你操做關係是會無端多產生一些update語句,好比你使用上面的例子保存一個customer對象,它關聯了2order 象,它不但會生成3insert語句(用於插入數據),還會生成2update語句(將關聯的order對象的customer_id更新爲本身的主 鍵值),你想一想要是一個customer對象包含幾萬了order對象(購物狂),那麼每次保存它得要多生成幾萬條update語句,這個就是很嚴重的性 能問題了。

   爲何Hibernate會產生update語句呢?那是Hibernate太主動,太熱情,太負責的表現,它怕你出現錯誤,例若有幾萬個order 象須要關聯到customer對象上,這就須要調用order.setCustomer(customer);,幾萬個對象這不是人能夠不放錯的完成的。 因此Hibernate怕你出錯忘記調用這個方法,因此他將會在order對象保存完畢後將全部關聯對象的customer_id字段更新一遍,確保正確 性,這樣也就產生上面的性能問題。

  將"inverse"設置爲false後,你能夠嘗試設置order1.setCustomer(null),它依然會正確的將customer的主鍵值完美的插入到ordercustomer_id字段上,只是會多一條update語句。
 

"cascade"屬性

   "cascade"-直譯過來就是"級聯、串聯"的意思,書面化的解釋爲"該屬性會使咱們在操做主對象時,同時Hibernate幫助咱們完成從屬對象 相應的操做(好比,有CustomerOrder這兩張表,關係爲一對多,只使用JDBC刪除Customer表中的一行記錄時,咱們還須要手動的將 Order表中與之關聯的記錄全都刪除,使用Hibernate'cascade'屬性後,當咱們刪除一條Customer記錄時,Hibernate 會幫助咱們完成相應Order表記錄的刪除工做,方便了咱們的工做)"

 

 

 總結

   使用"inverse"這個屬性時,要考慮清楚關係,否則你的系統就會有大的性能問題(不過我可能想不清楚,如今仍是一個普通大學生沒什麼實戰經驗 -_-!!,要繼續努力~_~),書本上和一些牛人建議,關係通常由"多方"維護,當遇到"多對多"時怎麼辦,其實多對多久是兩個"一對多",隨意設置一 "inverse""true"就能夠了,不要兩方都設置或都不設置(囧,我開始就是死板這樣的設置)。而是用"cascade"屬性時,主對象( )通常設置爲"all",而多方不建議設置包含delete操做的選項,建議設置多方爲"save-update",這是由於你刪除一方,多方已經沒有 存在的意義了,而刪除多方不能表明一方沒意義了(例如,消費者和訂單)。最後,"cascade"操做的是兩張表的記錄或兩端的對象, "inverse"操做的是兩張表的關係或兩個對象的關係。

相關文章
相關標籤/搜索