对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属性是否改变,也不管user的name改变是否影响到了他和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在发现acct1的bal发生改变后会自动执行
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,只要任意一方属性变了就维护,不管这个变更是否影响到了关系。