hibernate inverse使用释疑


总是令你的集合变量在配置文件中对应的映射元素的Inverse=true吗?

有许多hibernate的文章尝试用hibernate的官方术语来解释“inverse”,但是这很难理解(至少对我来说)。有少数文章甚至建议读者不去理会Inverse的含义,只要记住令集合变量在配置文件中对应的映射元素的inverse属性为true.


“令集合变量在配置文件中对应的映射元素的inverse属性为true.”的说法也不能说它是错的,但是不要让它影响你去发现inverse的精华所在,尝试着去发现它优化hibernate执行效率的精华吧。


inverse的作用是什么?


inverse是Hibernate中最令人困惑的关键字,至少我用了很长时间才弄清它的作用和使用方法。"inverse"关键字在一对多关系和多对多关系中被声明使用(在多对一中没有inverse关键字)。它的取值决定了具有关联关系(一对多或多对多)的两个实体类哪一个负责维护二者之间的关系。


"inverse",应该改成“relationship owner"吗?

在hibernate,只有“关系的拥有者”才能维护两个实体类之间的关联关系(一对多或多对多)。“inverse”关键字创建的目的是指明哪一边(实体类)是关系的拥有者。
然而“inverse”关键字生涩难懂,我建议将它改为“ relationship_owner

总之,inverse="true"说明当前配置文件对应的实体类不是关系的拥有者,而其对应的关联实体类是关系的拥有者(也就是inverse属性所在元素对应的集合变量引用的实体类为关系的拥有者),反之相反。


1.一对多关系
这是具有一对多关系表的设计,一个STOCK表记录可以被STOCK_DAILY_RECORD表中的多条记录引用。


2.hibernate的实现

hibernate xml映射文件的实现

File : Stock.java

public class Stock implements java.io.Serializable {
   ...
   private Set<StockDailyRecord> stockDailyRecords = 
						new HashSet<StockDailyRecord>(0);
   ...


File : StockDailyRecord.java

public class StockDailyRecord implements java.io.Serializable {
   ...
   private Stock stock;
   ...


File : Stock.hbm.xml

<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" ...>
    ...
    <set name="stockDailyRecords" table="stock_daily_record" fetch="select">
        <key>
            <column name="STOCK_ID" not-null="true" />
        </key>
        <one-to-many class="com.mkyong.common.StockDailyRecord" />
    </set>
    ...


File : StockDailyRecord.hbm.xml

<hibernate-mapping>
  <class name="com.mkyong.common.StockDailyRecord" table="stock_daily_record" ...>
  ...
  <many-to-one name="stock" class="com.mkyong.common.Stock">
       <column name="STOCK_ID" not-null="true" />
  </many-to-one>
  ...

3. inverse = true / false

下面展示了inverse 关键字在一对多关系上的应用。这里有一个问题,如果对“Stock”对象进行save或者update操作,“Stock”对象应该更新“stockDailyRecords”吗?

File : Stock.hbm.xml

    <class name="com.mkyong.common.Stock" table="stock" ...>
    ...
    <set name="stockDailyRecords" table="stock_daily_record" inverse="{true/false}" fetch="select">
        <key>
            <column name="STOCK_ID" not-null="true" />
        </key>
        <one-to-many class="com.mkyong.common.StockDailyRecord" />
    </set>
    ...

1. inverse=”true”

如果在set元素中有inverse="true",它说明“stock_daily_record”是关系的拥有者,那么Stock将不能维护它与stock_daily_record对应的实体类对象间的关联关系。

<class name="com.mkyong.common.Stock" table="stock" ...>
    ...
	<set name="stockDailyRecords" table="stock_daily_record" inverse="true" >

2. inverse=”false”

如果在set元素中有inverse="false",它说明“stock”是关系的拥有者,Stock将维护它与stock_daily_record对应的实体类对象间的关联关系。

<class name="com.mkyong.common.Stock" table="stock" ...>
	...
	<set name="stockDailyRecords" table="stock_daily_record" inverse="false" >

看下面更多的例子:

4. inverse=”false”

如果inverse没有显示写出,Inverse默认取false.等同于:

<!--Stock.hbm.xml-->
<class name="com.mkyong.common.Stock" table="stock" ...>
	...
	<set name="stockDailyRecords" table="stock_daily_record" inverse="false">

它说明“stock”是关系的拥有者。


insert的例子

当一个“Stock”对象被保存,hiberante将生成三个sql语句,两个insert语句一个update语句。

    session.beginTransaction();
 
    Stock stock = new Stock();
    stock.setStockCode("7052");
    stock.setStockName("PADINI");
 
    StockDailyRecord stockDailyRecords = new StockDailyRecord();
    stockDailyRecords.setPriceOpen(new Float("1.2"));
    stockDailyRecords.setPriceClose(new Float("1.1"));
    stockDailyRecords.setPriceChange(new Float("10.0"));
    stockDailyRecords.setVolume(3000000L);
    stockDailyRecords.setDate(new Date());
 
    stockDailyRecords.setStock(stock);        
    stock.getStockDailyRecords().add(stockDailyRecords);
 
    session.save(stock);
    session.save(stockDailyRecords);
 
    session.getTransaction().commit();

输出…

Hibernate: 
    INSERT 
    INTO
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    VALUES
        (?, ?)
Hibernate: 
    INSERT 
    INTO
        mkyongdb.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    VALUES
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    UPDATE
        mkyongdb.stock_daily_record 
    SET
        STOCK_ID=? 
    WHERE
        RECORD_ID=?

Stock将通过stockDailyRecords变量来更新“stock_daily_record.STOCK_ID”,因为在这里Stock是关系的拥有者。

注意
第三个sql语句是多余的

Update 例子 …

当一个“Stock”对象被更新,hibernate将生成两个sql语句,一个insert语句和一个update

    session.beginTransaction();
 
    Stock stock = (Stock)session.get(Stock.class, 57);
 
    StockDailyRecord stockDailyRecords = new StockDailyRecord();
    stockDailyRecords.setPriceOpen(new Float("1.2"));
    stockDailyRecords.setPriceClose(new Float("1.1"));
    stockDailyRecords.setPriceChange(new Float("10.0"));
    stockDailyRecords.setVolume(3000000L);
    stockDailyRecords.setDate(new Date());
 
    stockDailyRecords.setStock(stock);        
    stock.getStockDailyRecords().add(stockDailyRecords);
 
    session.save(stockDailyRecords);
    session.update(stock);
 
    session.getTransaction().commit();

输出...

Hibernate: 
    INSERT 
    INTO
        mkyongdb.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    VALUES
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    UPDATE
        mkyongdb.stock_daily_record 
    SET
        STOCK_ID=? 
    WHERE
        RECORD_ID=?

注意
第二个语句是多余的
5. inverse=”true”

如果inverse=“true”

<!--Stock.hbm.xml-->
<class name="com.mkyong.common.Stock" table="stock" ...>
	...
	<set name="stockDailyRecords" table="stock_daily_record" inverse="true">

现在,它说明“stockDailyRecords”(也就是StockDailyRecord实体类) 是关系的拥有者,“stock”将不能维护二者之间的关联关系。

Insert 例子 …

当一个“Stock”对象被保存,hibernate将生成两个sql语句

    session.beginTransaction();
 
    Stock stock = new Stock();
    stock.setStockCode("7052");
    stock.setStockName("PADINI");
 
    StockDailyRecord stockDailyRecords = new StockDailyRecord();
    stockDailyRecords.setPriceOpen(new Float("1.2"));
    stockDailyRecords.setPriceClose(new Float("1.1"));
    stockDailyRecords.setPriceChange(new Float("10.0"));
    stockDailyRecords.setVolume(3000000L);
    stockDailyRecords.setDate(new Date());
 
    stockDailyRecords.setStock(stock);        
    stock.getStockDailyRecords().add(stockDailyRecords);
 
    session.save(stock);
    session.save(stockDailyRecords);
 
    session.getTransaction().commit();


输出…

Hibernate: 
    INSERT 
    INTO
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    VALUES
        (?, ?)
Hibernate: 
    INSERT 
    INTO
        mkyongdb.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    VALUES
        (?, ?, ?, ?, ?, ?)


Update 例子…

当一个“Stock”对象被更新,hibernate将生成一个Sql语句

    session.beginTransaction();
 
    Stock stock = (Stock)session.get(Stock.class, 57);
 
    StockDailyRecord stockDailyRecords = new StockDailyRecord();
    stockDailyRecords.setPriceOpen(new Float("1.2"));
    stockDailyRecords.setPriceClose(new Float("1.1"));
    stockDailyRecords.setPriceChange(new Float("10.0"));
    stockDailyRecords.setVolume(3000000L);
    stockDailyRecords.setDate(new Date());
 
    stockDailyRecords.setStock(stock);        
    stock.getStockDailyRecords().add(stockDailyRecords);
 
    session.save(stockDailyRecords);
    session.update(stock);
 
    session.getTransaction().commit();


输出…

Hibernate: 
    INSERT 
    INTO
        mkyongdb.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    VALUES
        (?, ?, ?, ?, ?, ?)


inverse vs cascade
许多人喜欢拿inverse和cascade进行比较,但是它们是两个完全不同的概念,二者不同请浏览 differential here
总结

理解Inverse的本质含义是为了优化你的hibernate代码,它可以避免许多不必要的update语句,如上述的“inverset=ture下的insert 与update的例子”。

最后记住:inverse=“true”告诉hibernate具有关联关系的两个实体类哪一个是维护二者关系的关系拥有者。


原文:http://www.mkyong.com/hibernate/inverse-true-example-and-explanation/


个人阅读后对inverse=true的理解:

inverse=true应该从数据库表来看(当然这有点违反了hibernate的设计初衷了),即哪个表是外键所在的表,那么这个表

对应的实体类就应该是“关系的拥有者”,进而这个实体类对应的关联实体类的xml 映射文件就应该采用inverse=true.


  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值