总是令你的集合变量在配置文件中对应的映射元素的Inverse=true吗?
有许多hibernate的文章尝试用hibernate的官方术语来解释“inverse”,但是这很难理解(至少对我来说)。有少数文章甚至建议读者不去理会Inverse的含义,只要记住令集合变量在配置文件中对应的映射元素的inverse属性为true.
“令集合变量在配置文件中对应的映射元素的inverse属性为true.”的说法也不能说它是错的,但是不要让它影响你去发现inverse的精华所在,尝试着去发现它优化hibernate执行效率的精华吧。
inverse的作用是什么?
inverse是Hibernate中最令人困惑的关键字,至少我用了很长时间才弄清它的作用和使用方法。"inverse"关键字在一对多关系和多对多关系中被声明使用(在多对一中没有inverse关键字)。它的取值决定了具有关联关系(一对多或多对多)的两个实体类哪一个负责维护二者之间的关系。
"inverse",应该改成“relationship owner"吗?
然而“inverse”关键字生涩难懂,我建议将它改为“ relationship_owner”
总之,inverse="true"说明当前配置文件对应的实体类不是关系的拥有者,而其对应的关联实体类是关系的拥有者(也就是inverse属性所在元素对应的集合变量引用的实体类为关系的拥有者),反之相反。
1.一对多关系
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和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.