Hibernate inverse 作用 inverse="true" 作用
2012-02-01 16:17
453 查看
我们引用一个一对多的bag类型关联说明这个问题:
代码:
view
plaincopy
to clipboardprint?
public class Item implements Serializable
{
private Integer
itemId;
private String
itemName;
private Collection<Bid>
bids = new ArrayList<Bid>();
view
plaincopy
to clipboardprint?
/**
*
出价
*
@author partner4java
*
*/
public class Bid implements Serializable
{
private Integer
bidId;
private Double
bidMoeny;
private Item
item;
配置文件:
view
plaincopy
to clipboardprint?
<class name="Item" table="ITEM">
<id name="itemId" column="ITEM_ID" type="integer">
<generator class="native"/>
</id>
<property name="itemName" type="string" column="ITEM_NAME"/>
lt;bag
name="bids" cascade="save-update">
<!--
注意column="ITEM_ID_M"名称故意和Item主键不一致,这里是维护端生成的字段名称
-->
<key
column="ITEM_ID_M"></key>
<one-to-many class="Bid"/>
lt;/bag>
</class>
view
plaincopy
to clipboardprint?
<class name="Bid" table="BID">
<id
name="bidId" column="BID_ID" type="integer">
<generator class="native"/>
</id>
<property
name="bidMoeny" type="double"></property>
<!--
注意column="ITEM_ID_M"名称故意和Item主键不一致,这里是说明一的一端的表,需要生成的对应关联字段是什么
KEY
`FK100DD8434F24F` (`ITEM_ID_M`),
CONSTRAINT
`FK100DD8434F24F` FOREIGN KEY (`ITEM_ID_M`) REFERENCES `item` (`ITEM_ID`) -->
<many-to-one
name="item" column="ITEM_ID_M"
class="Item" not-null="true"></many-to-one>
</class>
执行插入:
view
plaincopy
to clipboardprint?
Item
item = new Item("hello");
Bid
bid = new Bid(12D);
item.getBids().add(bid);
//不添加这个报错:not-null
property references a null or transient value(因为添加了不能为空)
//<name="bids"
inverse="true" cascade="save-update">也决定了,维护端是Bid的item属性,所以要告诉Bid的item属性item的存在
//要知道这个东西和cascade="save-update"并不想干,cascade只是负责是否级联保存的,和表之间的关系由谁维护无关
bid.setItem(item);
session.save(item);
hibernate打印sql:
Hibernate: insert into ITEM (ITEM_NAME) values (?)
Hibernate: insert into BID (bidMoeny, ITEM_ID_M) values (?, ?)
Hibernate: update BID set ITEM_ID_M=? where BID_ID=?
那么你看到了多打印了一条sql,最后一条是荣誉的。
原因:
在操作两个实例之间的连接时,如果没有inverse属性,hibernate会试图执行两个不同的SQL语句,这两者更新
同一个外键列。通过指定inverse="true",显示地告诉hibernate连接的哪一端不应该与数据库同步。在这个例子
中,告诉hibernate他应该把在关联的Bid端所做的变化传播到数据库,忽略只对bids集合所做的变化。
如下:
view
plaincopy
to clipboardprint?
<class name="Item" table="ITEM">
<id name="itemId" column="ITEM_ID" type="integer">
<generator class="native"/>
</id>
<property name="itemName" type="string" column="ITEM_NAME"/>
lt;bag
name="bids" inverse="true" cascade="save-update">
<!--
注意column="ITEM_ID_M"名称故意和Item主键不一致,这里是维护端生成的字段名称
-->
<key
column="ITEM_ID_M"></key>
<one-to-many class="Bid"/>
lt;/bag>
</class>
执行相同插入:
hibernate打印sql:
Hibernate: insert into ITEM (ITEM_NAME) values (?)
Hibernate: insert into BID (bidMoeny, ITEM_ID_M) values (?, ?)
那么有些时候,是不能添加inverse="true"的,比如保存有序的list集合:
添加:insert="false" update="false"
但是这么做还是会打印三条sql,不添加则会报错
Repeated column in mapping for entity: cn.partner4java.hibernate.onetomany2.Bid column: ITEM_ID (should be mapped with insert="false" update="false")
如:
view
plaincopy
to clipboardprint?
<class name="Item" table="ITEM">
<id
name="itemId" column="ITEM_ID" type="integer">
<generator class="native"/>
</id>
<property
name="itemName" type="string" column="ITEM_NAME"/>
<!--
没有在集合中加入inverse="true,因为hibernate忽略反向集合的状态!
但是这一次,集合包含了正确的更新数据库所需要的信息:它的元素的位置。
如果只有每个Bid实例的状态被认为是同步的,集合又是方向的并且被忽略,
那么hibernate就没有值给BID_POSITOIN了-->
<list
name="bids" cascade="save-update">
<key
column="ITEM_ID" not-null="true"></key>
<list-index
column="BID_POSITOIN"></list-index>
<one-to-many class="Bid"/>
</list>
</class>
<class name="Bid" table="BID">
<id
name="bidId" column="BID_ID" type="integer">
<generator class="native"/>
</id>
<property
name="bidMoeny" type="double"></property>
<!--
如果通过被索引的集合映射双向的一对多实体关联(映射和数组也是这样),
就必须转换为方向段。无法被索引的集合变成inverse="true"。集合变成了
负责状态同步,并且一的端Bid必须变成反向。然而,多对一的映射没有
inverse="true",因此需要在<many-to-one>中模拟这一模拟这一属性:
设置insert="false" update="false"
这俩个属性一起使用,实际上使属性变成了只读。关联的这一端因此被任何写操作忽略,
当内存状态与数据库同步时,集合的状态就是相关的状态。你已经转换了关联的方向/非方向端,
如果从set或者bag转换为list,这个是必要的条件。
-->
<many-to-one
name="item" column="ITEM_ID_M"
class="Item" not-null="true"
insert="false" update="false"></many-to-one>
</class>
双向对多对时:
代码:
view
plaincopy
to clipboardprint?
public class Category implements Serializable
{
private Integer
categoryId;
private String
name;
private Set<Item>
items = new HashSet<Item>();
view
plaincopy
to clipboardprint?
public class Item implements Serializable
{
private Integer
itemId;
private String
itemName;
private Set<Category>
categories = new HashSet<Category>();
配置文件:
view
plaincopy
to clipboardprint?
<class name="Category" table="Category">
<id
name="categoryId" column="CATEGORY_ID" type="integer">
<generator class="native"/>
</id>
<property
name="name" type="string" column="name"/>
<set
name="items" table="CATEGORY_ITEM" inverse="true" cascade="save-update">
<key
column="CATEGORY_ID"></key>
<many-to-many
column="ITEM_ID" class="Item"></many-to-many>
</set>
</class>
view
plaincopy
to clipboardprint?
<class name="Item" table="ITEM">
<id
name="itemId" column="ITEM_ID" type="integer">
<generator class="native"/>
</id>
<property
name="itemName" type="string" column="ITEM_NAME"/>
<set
name="categories" table="CATEGORY_ITEM" cascade="save-update">
<key
column="ITEM_ID"></key>
<many-to-many
column="CATEGORY_ID" class="Category"></many-to-many>
</set>
</class>
插入代码:
view
plaincopy
to clipboardprint?
public class HelloWorld
{
public static void main(String[]
args) {
// insert();
// insert2();
insert3();
}
private static void insert()
{
Configuration
configuration = new Configuration().configure();
SessionFactory
sessionFactory = configuration.buildSessionFactory();
Session
session = sessionFactory.openSession();
Transaction
tr = session.beginTransaction();
Item
item = new Item("item");
Category
category1 = new Category("category1");
item.getCategories().add(category1);
Category
category2 = new Category("category2");
item.getCategories().add(category2);
session.save(item);
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
// Hibernate:
insert into Category (name) values (?)
// Hibernate:
insert into Category (name) values (?)
// Hibernate:
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
// Hibernate:
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
tr.commit();
session.close();
sessionFactory.close();
}
private static void insert2()
{
Configuration
configuration = new Configuration().configure();
SessionFactory
sessionFactory = configuration.buildSessionFactory();
Session
session = sessionFactory.openSession();
Transaction
tr = session.beginTransaction();
Category
category = new Category("category1");
Item
item1 = new Item("item1");
category.getItems().add(item1);
Item
item2 = new Item("item1");
category.getItems().add(item2);
session.save(category);
//inverse="true"的一端,忽略对中间库的影响
// Hibernate:
insert into Category (name) values (?)
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
tr.commit();
session.close();
sessionFactory.close();
}
private static void insert3()
{
Configuration
configuration = new Configuration().configure();
SessionFactory
sessionFactory = configuration.buildSessionFactory();
Session
session = sessionFactory.openSession();
Transaction
tr = session.beginTransaction();
Category
category = new Category("category1");
Item
item1 = new Item("item1");
category.getItems().add(item1);
Item
item2 = new Item("item1");
category.getItems().add(item2);
//必须存在,才会影响中间表,因为inverse="false"的一端,才会影响中间库的变化
item1.getCategories().add(category);
item2.getCategories().add(category);
session.save(category);
// Hibernate:
insert into Category (name) values (?)
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
// Hibernate:
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
// Hibernate:
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
tr.commit();
session.close();
sessionFactory.close();
}
}
代码:
view
plaincopy
to clipboardprint?
public class Item implements Serializable
{
private Integer
itemId;
private String
itemName;
private Collection<Bid>
bids = new ArrayList<Bid>();
view
plaincopy
to clipboardprint?
/**
*
出价
*
@author partner4java
*
*/
public class Bid implements Serializable
{
private Integer
bidId;
private Double
bidMoeny;
private Item
item;
配置文件:
view
plaincopy
to clipboardprint?
<class name="Item" table="ITEM">
<id name="itemId" column="ITEM_ID" type="integer">
<generator class="native"/>
</id>
<property name="itemName" type="string" column="ITEM_NAME"/>
lt;bag
name="bids" cascade="save-update">
<!--
注意column="ITEM_ID_M"名称故意和Item主键不一致,这里是维护端生成的字段名称
-->
<key
column="ITEM_ID_M"></key>
<one-to-many class="Bid"/>
lt;/bag>
</class>
view
plaincopy
to clipboardprint?
<class name="Bid" table="BID">
<id
name="bidId" column="BID_ID" type="integer">
<generator class="native"/>
</id>
<property
name="bidMoeny" type="double"></property>
<!--
注意column="ITEM_ID_M"名称故意和Item主键不一致,这里是说明一的一端的表,需要生成的对应关联字段是什么
KEY
`FK100DD8434F24F` (`ITEM_ID_M`),
CONSTRAINT
`FK100DD8434F24F` FOREIGN KEY (`ITEM_ID_M`) REFERENCES `item` (`ITEM_ID`) -->
<many-to-one
name="item" column="ITEM_ID_M"
class="Item" not-null="true"></many-to-one>
</class>
执行插入:
view
plaincopy
to clipboardprint?
Item
item = new Item("hello");
Bid
bid = new Bid(12D);
item.getBids().add(bid);
//不添加这个报错:not-null
property references a null or transient value(因为添加了不能为空)
//<name="bids"
inverse="true" cascade="save-update">也决定了,维护端是Bid的item属性,所以要告诉Bid的item属性item的存在
//要知道这个东西和cascade="save-update"并不想干,cascade只是负责是否级联保存的,和表之间的关系由谁维护无关
bid.setItem(item);
session.save(item);
hibernate打印sql:
Hibernate: insert into ITEM (ITEM_NAME) values (?)
Hibernate: insert into BID (bidMoeny, ITEM_ID_M) values (?, ?)
Hibernate: update BID set ITEM_ID_M=? where BID_ID=?
那么你看到了多打印了一条sql,最后一条是荣誉的。
原因:
在操作两个实例之间的连接时,如果没有inverse属性,hibernate会试图执行两个不同的SQL语句,这两者更新
同一个外键列。通过指定inverse="true",显示地告诉hibernate连接的哪一端不应该与数据库同步。在这个例子
中,告诉hibernate他应该把在关联的Bid端所做的变化传播到数据库,忽略只对bids集合所做的变化。
如下:
view
plaincopy
to clipboardprint?
<class name="Item" table="ITEM">
<id name="itemId" column="ITEM_ID" type="integer">
<generator class="native"/>
</id>
<property name="itemName" type="string" column="ITEM_NAME"/>
lt;bag
name="bids" inverse="true" cascade="save-update">
<!--
注意column="ITEM_ID_M"名称故意和Item主键不一致,这里是维护端生成的字段名称
-->
<key
column="ITEM_ID_M"></key>
<one-to-many class="Bid"/>
lt;/bag>
</class>
执行相同插入:
hibernate打印sql:
Hibernate: insert into ITEM (ITEM_NAME) values (?)
Hibernate: insert into BID (bidMoeny, ITEM_ID_M) values (?, ?)
那么有些时候,是不能添加inverse="true"的,比如保存有序的list集合:
添加:insert="false" update="false"
但是这么做还是会打印三条sql,不添加则会报错
Repeated column in mapping for entity: cn.partner4java.hibernate.onetomany2.Bid column: ITEM_ID (should be mapped with insert="false" update="false")
如:
view
plaincopy
to clipboardprint?
<class name="Item" table="ITEM">
<id
name="itemId" column="ITEM_ID" type="integer">
<generator class="native"/>
</id>
<property
name="itemName" type="string" column="ITEM_NAME"/>
<!--
没有在集合中加入inverse="true,因为hibernate忽略反向集合的状态!
但是这一次,集合包含了正确的更新数据库所需要的信息:它的元素的位置。
如果只有每个Bid实例的状态被认为是同步的,集合又是方向的并且被忽略,
那么hibernate就没有值给BID_POSITOIN了-->
<list
name="bids" cascade="save-update">
<key
column="ITEM_ID" not-null="true"></key>
<list-index
column="BID_POSITOIN"></list-index>
<one-to-many class="Bid"/>
</list>
</class>
<class name="Bid" table="BID">
<id
name="bidId" column="BID_ID" type="integer">
<generator class="native"/>
</id>
<property
name="bidMoeny" type="double"></property>
<!--
如果通过被索引的集合映射双向的一对多实体关联(映射和数组也是这样),
就必须转换为方向段。无法被索引的集合变成inverse="true"。集合变成了
负责状态同步,并且一的端Bid必须变成反向。然而,多对一的映射没有
inverse="true",因此需要在<many-to-one>中模拟这一模拟这一属性:
设置insert="false" update="false"
这俩个属性一起使用,实际上使属性变成了只读。关联的这一端因此被任何写操作忽略,
当内存状态与数据库同步时,集合的状态就是相关的状态。你已经转换了关联的方向/非方向端,
如果从set或者bag转换为list,这个是必要的条件。
-->
<many-to-one
name="item" column="ITEM_ID_M"
class="Item" not-null="true"
insert="false" update="false"></many-to-one>
</class>
双向对多对时:
代码:
view
plaincopy
to clipboardprint?
public class Category implements Serializable
{
private Integer
categoryId;
private String
name;
private Set<Item>
items = new HashSet<Item>();
view
plaincopy
to clipboardprint?
public class Item implements Serializable
{
private Integer
itemId;
private String
itemName;
private Set<Category>
categories = new HashSet<Category>();
配置文件:
view
plaincopy
to clipboardprint?
<class name="Category" table="Category">
<id
name="categoryId" column="CATEGORY_ID" type="integer">
<generator class="native"/>
</id>
<property
name="name" type="string" column="name"/>
<set
name="items" table="CATEGORY_ITEM" inverse="true" cascade="save-update">
<key
column="CATEGORY_ID"></key>
<many-to-many
column="ITEM_ID" class="Item"></many-to-many>
</set>
</class>
view
plaincopy
to clipboardprint?
<class name="Item" table="ITEM">
<id
name="itemId" column="ITEM_ID" type="integer">
<generator class="native"/>
</id>
<property
name="itemName" type="string" column="ITEM_NAME"/>
<set
name="categories" table="CATEGORY_ITEM" cascade="save-update">
<key
column="ITEM_ID"></key>
<many-to-many
column="CATEGORY_ID" class="Category"></many-to-many>
</set>
</class>
插入代码:
view
plaincopy
to clipboardprint?
public class HelloWorld
{
public static void main(String[]
args) {
// insert();
// insert2();
insert3();
}
private static void insert()
{
Configuration
configuration = new Configuration().configure();
SessionFactory
sessionFactory = configuration.buildSessionFactory();
Session
session = sessionFactory.openSession();
Transaction
tr = session.beginTransaction();
Item
item = new Item("item");
Category
category1 = new Category("category1");
item.getCategories().add(category1);
Category
category2 = new Category("category2");
item.getCategories().add(category2);
session.save(item);
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
// Hibernate:
insert into Category (name) values (?)
// Hibernate:
insert into Category (name) values (?)
// Hibernate:
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
// Hibernate:
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
tr.commit();
session.close();
sessionFactory.close();
}
private static void insert2()
{
Configuration
configuration = new Configuration().configure();
SessionFactory
sessionFactory = configuration.buildSessionFactory();
Session
session = sessionFactory.openSession();
Transaction
tr = session.beginTransaction();
Category
category = new Category("category1");
Item
item1 = new Item("item1");
category.getItems().add(item1);
Item
item2 = new Item("item1");
category.getItems().add(item2);
session.save(category);
//inverse="true"的一端,忽略对中间库的影响
// Hibernate:
insert into Category (name) values (?)
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
tr.commit();
session.close();
sessionFactory.close();
}
private static void insert3()
{
Configuration
configuration = new Configuration().configure();
SessionFactory
sessionFactory = configuration.buildSessionFactory();
Session
session = sessionFactory.openSession();
Transaction
tr = session.beginTransaction();
Category
category = new Category("category1");
Item
item1 = new Item("item1");
category.getItems().add(item1);
Item
item2 = new Item("item1");
category.getItems().add(item2);
//必须存在,才会影响中间表,因为inverse="false"的一端,才会影响中间库的变化
item1.getCategories().add(category);
item2.getCategories().add(category);
session.save(category);
// Hibernate:
insert into Category (name) values (?)
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
// Hibernate:
insert into ITEM (ITEM_NAME) values (?)
// Hibernate:
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
// Hibernate:
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
tr.commit();
session.close();
sessionFactory.close();
}
}
相关文章推荐
- hibernate inverse 作用 inverse="true" 作用
- Hibernate中inverse="true"的理解
- Hibernate中inverse="true"
- hibernate,inverse="true"的问题
- Hibernate中单向一对多,单向多对一,双向一对多 inverse="true" casecade="save-update"的理解
- Hibernate中inverse="true"的理解
- hibernate inverse="true"
- Hibernate学习笔记(1)-Hibernate中inverse="true"的理解
- Hibernate中inverse="true"的理解
- 由一对多引谈Hibernate的inverse="true"属性
- 关于Hibernate中inverse=true的转载
- Spring MVC中解决中文乱码问题时useBodyEncodingForURI="true"的作用
- tomcat context.xml文件配置<Loader delegate="true" />作用
- android:stateNotNeeded="true"的作用
- hibernate中inverse作用
- 关于Hibernate中inverse=true
- JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-006类型转换器( @Converter(autoApply = true) 、type="converter:qualified.ConverterName" )
- Hibernate一对多双向关联及inverse的作用
- android:clearTaskOnLaunch="true"的作用
- inverse="true" 放弃维护关联关系=true