Hibernate一对多双向关联及inverse的作用

本文探讨了Hibernate中一对多双向关联的实现方式,并通过具体示例分析了inverse属性的影响。inverse属性决定了一对多关联中哪一方负责维护关联关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                 Hibernate一对多双向关联及inverse的作用

       在测试Hibernate的一对多双向关联映射时,碰到很有趣的问题,跟inverse属性直接相关。

1、People.hbm.xml

<hibernate-mapping  default-lazy="false">  
   
<class name="com.persistent.People" table="people">     
     
<id name="id" column="peopleId" unsaved-value="0">    
        
<generator class="increment">        
        
</generator>    
     
</id>     
     
<property name="name" column="name"></property>     
     
<set name="addresses" cascade="save-update">
        
<key column="peopleId" not-null="true" />
        
<one-to-many class="com.persistent.Address"/>
     
</set>     
   
</class>
</hibernate-mapping>

2、Address.hbm.xml

<hibernate-mapping>
  
<class name="com.persistent.Address" table="address">  
    
<id name="id" column="addressId" unsaved-value="0">
        
<generator class="increment">
        
</generator>
    
</id>    
    
<many-to-one name="people" column="peopleId" insert="false" update="false"></many-to-one>    
    
<property name="addressName" column="addressName"></property>    
    
<property name="codeNumber" column="codeNumber"></property>    
  
</class>  
</hibernate-mapping>

3、People.java和Address.java

public class People {    
  
private long id;
  
private String name;
  
private Set addresses = new HashSet();
  ...
}


public class Address {    
  
private long id;
  
private People people;
  
private String addressName;
  
private String codeNumber;
  ...
}
        

4、数据库结构

  people表:{peopleId,name}

  address表:{addressId,peopleId,addressName,codeNumber}

5、测试代码

People people = new People();
people.setName(
"linda");
Address address 
= new Address();
address.setAddressName(
"yunnan");
address.setCodeNumber(
"564123");
address.setPeople(people);
people.getAddresses().add(address);
Session session 
= HibernateSessionFactory.getSession();
session.beginTransaction();
session.save(people);
session.getTransaction().commit();

6、运行结果

      上面测试代码运行起来正确:

Hibernate: select max(peopleId) from people
Hibernate: select max(addressId) from address
Hibernate: insert into people (name, peopleId) values (?, ?)
Hibernate: insert into address (addressName, codeNumber, peopleId, addressId) values (?, ?, ?, ?)
Hibernate: update address set peopleId=? where addressId=?

      如果将People.hbm.xml映射改写一下:

<set name="addresses" cascade="save-update" inverse="true">
        
<key column="peopleId" not-null="true" />
        
<one-to-many class="com.persistent.Address"/>
</set>

      不同之处在于添加了inverse="true",结果:
Hibernate: select max(peopleId) from people
Hibernate: select max(addressId) from address
Hibernate: insert into people (name, peopleId) values (?, ?)
Hibernate: insert into address (addressName, codeNumber, addressId) values (?, ?, ?)

      可以看到,peopleId并没有写入到关联的address当中,数据库address表中相应记录的peopleId字段为空。

7、分析

      在Hibernate中,术语inverse是反转的意思,在关联关系中,inverse="false"为主控方,由主控方负责维护对象的关联关系。所以上面的映射文件改动之后,address为主控方,people为被控方,但是测试代码只进行了一个保存操作session.save(people),这是针对people的,因此无法正确级联保存address。而原来的映射文件中(虽然没有明确指明,Hibernate默认inverse="false"),people为主控方,因此保存people时它会保证关联的address的正确保存。

      也就是说,Hibernate仅仅按照主控方对象的状态的变化来同步更新数据库。按照原来的映射文件,people.getAddresses().add(address),即主控方对象的状态发生了改变,因此数据库会跟着对象状态的变化来同步更新数据库;而address.setPeople(people),即被控方对象的状态发生了改变,它是不能触发对象和数据库的同步更新的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值