现在的位置: 首页 > 综合 > 正文

hibernate一对多关系采用外键映射时使用inverse的几种情况

2018年01月24日 ⁄ 综合 ⁄ 共 5228字 ⁄ 字号 评论关闭

hibernate关系的维护比较头疼,遂总结下做个备份。

什么时候维护关系:当关联双方对象有一方的属性发生变化时。

举例:一个用户有多个账户,类User和类Account是一对多的双向关联关系。

User类:

public class User
{

    private Long oid;

    private String uid;

    private String name;

    //关联属性

    private Set accts = new HashSet();

......

}

Account类:

public class Account
{

    private Long oid;

    private String acctNo;

    private double bal;

    //关联属性

    private User owner;

......

}

mq_user:

mysql> desc mq_user;

+-----------+--------------+------+-----+---------+----------------+

| Field     | Type         | Null | Key | Default | Extra          |

+-----------+--------------+------+-----+---------+----------------+

| OID       | bigint(20)   | NO   | PRI | NULL    | auto_increment |

| USER_ID   | varchar(255) | NO   | UNI | NULL    |                |

| USER_NAME | varchar(255) | NO   |     | NULL    |                |

+-----------+--------------+------+-----+---------+----------------+

mq_acct2

mysql> desc mq_acct2;

+--------+--------------+------+-----+---------+----------------+

| Field | Type         | Null | Key | Default | Extra          |

+--------+--------------+------+-----+---------+----------------+

| OID    | bigint(20)   | NO   | PRI | NULL    | auto_increment |

| ACCTNO | varchar(255) | NO   | UNI | NULL    |                |

| BAL    | double       | NO   |     | NULL    |                |

| FID    | bigint(20)   | YES | MUL | NULL    |                |

+--------+--------------+------+-----+---------+----------------+

映射文件:

User.hbm.xml:

<set name "accts" inverse "false" >

           <key column="FID" />

           <one-to-many class="Account" />

</set>

 

Account.hbm.xml:

<many-to-one name "owner"

              class "User"

              column "FID"/>

 

 

如果:Session s = HbnUtil.getSession();

     s.beginTransaction();

     Account acct1 = new Account("a01", 5000.0);

     User user = new User("u01","jack");

     user.getAccts().add(acct1);

     s.save(user);

     s.save(acct1);

     s.getTransaction().commit();

结果:Hibernate:

    insert

    into

        mq_user

        (USER_ID, USER_NAME)

    values

        (?, ?)

Hibernate:

    insert

    into

        mq_acct2

        (ACCTNO, BAL, FID)

    values

        (?, ?, ?)

Hibernate:

    update

        mq_acct2

    set

        FID=?

    where

        OID=?

 

说明:一对多双向关联中默认多的一方inverse=”false”,也就是说由多的一方维护关系。

这里把一的一方的inverse也改为false,并且在代码中不写acct1.setOwner(user)是为了测试一的一方是如何维护关系的。

在执行了insert into 语句以后,紧接着执行的update语句就是一的一方在维护关系。

从执行的过程还可以看出,维护关系的动作实际上是update而不是insert操作。

总结:1,多的一方总是维护且必须维护关系(many-to-one中没有inverse属性),一的一方可以选择维护或不维护。

---------------------------------------------------------------------

如果:Session s = HbnUtil.getSession();

     s.beginTransaction();

     Account acct1 = new Account("a01", 5000.0);

     User user = new User("u01","jack");

     user.getAccts().add(acct1);

     s.save(user);

     s.getTransaction().commit();

结果:Hibernate:

    insert

    into

        mq_user

        (USER_ID, USER_NAME)

    values

        (?, ?)

Hibernate:

    update

        mq_user

    set

        USER_ID=?,

        USER_NAME=?

    where

        OID=?

Hibernate:

    update

        mq_acct2

    set

        FID=?

    where

        OID=?

org.hibernate.TransientObjectException:

 

说明:去掉了对acct1的保存。抛异常。

      inverse是关系维护而不是级联操作(通过配置cascade属性可以让user被保存时级联acct1一起被保存),关系维护只会update

总结:2,关系维护只做update,不搞级联,所以要注意维护的数据是否已经在数据库中。

         除非做了级联create或者数据库中有被维护的数据,否则是要抛异常滴。

---------------------------------------------------------------------

如果:Account acct1 = new Account("a01", 5000.0);

     User user = new User("u01","jack");

     user.getAccts().add(acct1);

     s.save(user);

     s.save(acct1);

     user.setName("aaaaa");

结果:Hibernate:

    insert

    into

        mq_user

        (USER_ID, USER_NAME)

    values

        (?, ?)

Hibernate:

    insert

    into

        mq_acct2

        (ACCTNO, BAL, FID)

    values

        (?, ?, ?)

Hibernate:

    update

        mq_user

    set

        USER_ID=?,

        USER_NAME=?

    where

        OID=?

Hibernate:

    update

        mq_acct2

    set

        FID=?

    where

        OID=?

说明:因为user是一个持久化对象(session保存过),所以在user属性发生改变时,session会监测user属性是否改变并在改变后自动执行update
mq_user
。但不管acct1属性是否改变,也不管username改变是否影响到了他和acct1的关系,都会再维护一次。

---------------------------------------------------------------------

如果:Account acct1 = new Account("a01", 5000.0);

     User user = new User("u01","jack");

     user.getAccts().add(acct1);

     s.save(user);

     s.save(acct1);

     acct1.setBal(999);

结果:

Hibernate:

    insert

    into

        mq_user

        (USER_ID, USER_NAME)

    values

        (?, ?)

Hibernate:

    insert

    into

        mq_acct2

        (ACCTNO, BAL, FID)

    values

        (?, ?, ?)

Hibernate:

    update

        mq_acct2

    set

        ACCTNO=?,

        BAL=?,

        FID=?

    where

        OID=?

Hibernate:

    update

        mq_acct2

    set

        FID=?

    where

        OID=?

说明:因为acct1是持久化对象,所以session在发现acct1bal发生改变后会自动执行

update mq_acct2语句。随后负责维护关系的user一方会再维护一次关系。

------------------------------------------------------------------------------------ 

如果:Account acct1 = new Account("a01", 5000.0);

     User user = new User("u01","jack");

     user.getAccts().add(acct1);

     acct1.setOwner(user);

     s.save(user);

     s.save(acct1);

     acct1.setBal(999);

结果:Hibernate:

    insert

    into

        mq_user

        (USER_ID, USER_NAME)

    values

        (?, ?)

Hibernate:

    insert

    into

        mq_acct2

        (ACCTNO, BAL, FID)

    values

        (?, ?, ?)

Hibernate:

    update

        mq_acct2

    set

        ACCTNO=?,

        BAL=?,

        FID=?

    where

        OID=?

Hibernate:

    update

        mq_acct2

    set

        FID=?

    where

        OID=?

说明:如果双方是双向关联又各自都维护关系,那么当需要维护时会各自维护一次。

总结:3,实际运行时的对象如果不知道对方对象的存在(没有关联)就不会维护关系。

     4,只要任意一方属性变了就维护,不管这个变更是否影响到了关系。

抱歉!评论已关闭.