hibernate inverse使用释疑

来源:互联网 发布:余额宝优化理财怎么样 编辑:程序博客网 时间:2024/06/05 02:25

总是令你的集合变量在配置文件中对应的映射元素的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.