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

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

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一方会再维护一次关系。

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

<!--[endif]-->

如果: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,只要任意一方属性变了就维护,不管这个变更是否影响到了关系。