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

    技术2022-05-11  8

    在测试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 peopleHibernate: select max(addressId) from addressHibernate: 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 peopleHibernate: select max(addressId) from addressHibernate: 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),即被控方对象的状态发生了改变,它是不能触发对象和数据库的同步更新的。


    最新回复(0)