读完 Java对象持久化技术详解6.1节,写一下读书笔记:
多对一 单向关联 匹配 关系数据库中的外键参照关系。
在关系数据库中,只存在外键参照关系,而且是由many--->one,是单向关联。
以Customer和Order为例。
单向关联中,Order中包含一个customer属性。这样定义了一个Order到Customer的关联,是多对一的。Customer中未包含Order属性.
在Order.hbm.xml中,要进行关联映射Order类与ORDERS表。
单向关联中,Order中包含一个customer属性。这样定义了一个Order到Customer的关联,是多对一的。Customer中未包含Order属性.
在Order.hbm.xml中,要进行关联映射Order类与ORDERS表。
id------ID customer------CUSTOMER_ID
映射 customer------CUSTOMER_ID需要 使用 many-to-one
many-to-one用来建立customer属性和ORDERS表的外键CUSTOMER_ID之间的映射
<many-to-one
name = "customer" //待映射的持久化类的属性名
column = "CUSTOMER_ID" //设定和该属性对应的表的外键
class = "Customer" //设定该属性的类型
not-null = "true" //表示customer属性不能为null,默认为false
cascade = "all" //级联更新与Order类对象相关联的对象
/>
一个概念:
临时对象(transient)
刚刚通过new( )创建,并且未被持久化的对象。
Customer customer = new Customer(); //transient
session.save(customer); //执行完该语句后,customer成为持久化对象
//------------------不同的配置出现的不同情况-----------------------
cascade取默认值的情况
<many-to-one
Order order = new Order();
order.setCustomer(customer);
session.save(order);
Hibernate持久化order时, 不会自动持久化与其相关联的其他对象,因为没有显示设置cascade属性的相关值。
这样cascade取默认值none,当持久化order时,会执行类似如下语句:
insert into ORDERS (ID,CUSTOMER_ID) values (1,null )
这违反了数据库完整性约束,因为ORDERS表中设置的CUSTOMER_ID为 not null
抛出异常:
net.sf.hibernate.PropertyValueException: not-null property references a null or transient
value: Order.customer
删除 not-null = "true"后,
会把order与customer一起持久化。
insert into CUSTOMERS(ID,NAME) values( 1 , " haha")
insert into ORDERS( ID, CUSTOMER_ID) values (1,1 )
<many-to-one
Order order = new Order();
order.setCustomer(customer);
session.save(order);
Hibernate持久化order时,
insert into ORDERS (ID,CUSTOMER_ID) values (3,null )
这次成功持久化了order对象,不再抛出PropertyValueException,因为ORDERS表的CUSTOMER_ID允许null值出现
但当Hibernate自动清理(flush)缓存中所有持久化对象时,抛出新的异常:
net.sf.hibernate.TransientObjectException: object references an unsaved transient instance -
save the transient instance before flushing: Customer
flush -- Hibernate按照内存中持久化对象的状态 来同步更新数据库.
Hibernate发现持久化对象order引用transient对象customer,而ORDERS表中相应的记录的
CUSTOMER_ID字段为null,也就是说内存中的持久化对象的状态与数据库中的记录不一致。
而且在这种情况下,Hibernate没办法使两者同步,因为Hibernate不会自动持久化customer对象,
所以,Hibernate抛出 TransientObjectException异常。
这时需要设置cascade属性来解决问题
<many-to-one
name = "customer" //待映射的持久化类的属性名
column = "CUSTOMER_ID" //设定和该属性对应的表的外键
class = "Customer" //设定该属性的类型
cascade = "save-update" //当保存或更新当前对象时
//级联保存或更新与Order类对象相关联的对象
/>
这样当执行
Customer customer = new Customer(); //transient
customer.setName("haha");
Order order = new Order();
order.setCustomer(customer);
session.save(order);
name = "customer" //待映射的持久化类的属性名
column = "CUSTOMER_ID" //设定和该属性对应的表的外键
class = "Customer" //设定该属性的类型
/>
Customer customer = new Customer(); //transient
name = "customer" //待映射的持久化类的属性名
column = "CUSTOMER_ID" //设定和该属性对应的表的外键
class = "Customer" //设定该属性的类型
not-null = "true" //表示customer属性不能为null,默认为false
/>
Customer customer = new Customer(); //transient