您的位置:首页 > 其它

关于hibernate实现的set类问题

2013-05-07 12:43 453 查看
hibernate自实现的set类如persiterSet,在hibernate有很大的用处:

用例1:

public void test5() {
Session session = HibernateUtil.getInstance().getSession();
Transaction tx = null;
tx = session.beginTransaction();
Customer customer=null;

try {
//延迟加载下的customer是存在session中的
customer = (Customer)session.get(Customer.class, 7);

tx.commit();
}catch(Exception e) {
tx.rollback();
e.printStackTrace();
}finally {
session.close();
}

Session session1 = HibernateUtil.getInstance().getSession();
Transaction tx1 = null;
tx1 = session1.beginTransaction();
try {
session1.saveOrUpdate(customer);
tx1.commit();
}catch(Exception e) {
tx1.rollback();
e.printStackTrace();
}finally {
session1.close();
}
}

当执行saveOrUpdate()的时候不会发出任何语句。

当执行saveOrUpdate的时候只会发出一条更新customer的语句(上一条语句的更正)。

但是下面案例就不一样了:

public void test5() {
Session session = HibernateUtil.getInstance().getSession();
Transaction tx = null;
tx = session.beginTransaction();
Customer customer=null;

try {
//延迟加载下的customer是存在session中的
customer = (Customer)session.get(Customer.class, 11);
Hibernate.initialize(customer.getOrders());
tx.commit();
}catch(Exception e) {
tx.rollback();
e.printStackTrace();
}finally {
session.close();
}

Session session1 = HibernateUtil.getInstance().getSession();
Transaction tx1 = null;
tx1 = session1.beginTransaction();
try {
session1.saveOrUpdate(customer);
tx1.commit();
}catch(Exception e) {
tx1.rollback();
e.printStackTrace();
}finally {
session1.close();
}
}


发出语句:

Hibernate: update t_customer set name=? where customer_id=?
Hibernate: update t_order set order_num=?, customer_id=? where order_id=?
Hibernate: update t_order set order_num=?, customer_id=? where order_id=?
Hibernate: update t_order set order_num=?, customer_id=? where order_id=?
Hibernate: update t_order set order_num=?, customer_id=? where order_id=?
Hibernate: update t_order set order_num=?, customer_id=? where order_id=?
Hibernate: update t_order set order_num=?, customer_id=? where order_id=?


为什么会出现这样的情况呢?

其实这就是Hibernate自实现set的功能,这里仅仅是set的它的一个作用哦!

persiterSet中有个init即初始化标记,在案例1中由于没有初始化该set,因此在更新游离态的时候,Hibernate发现set中的初始化标记为false,即没初始化,那么此时hiberante会认定该customer中的set集合没有发生改变,更不会发出update order null.

如果显式的使用Hibernate.initialize(customer.getOrders());,那么会更新初始化标记,为true,那么执行saveOrUpdate的时候,就无法判断customer中的set集合中的orders有没有改变,因此会发出好多条Update order 语句。

下面还有一个比较好的例子,不能说是奇葩,只能说hibernate的延迟机制吧

public void test5() {
Session session = HibernateUtil.getInstance().getSession();
Transaction tx = null;
tx = session.beginTransaction();
Customer customer=null;

try {
//延迟加载下的customer是存在session中的
customer = (Customer)session.load(Customer.class, 7);

tx.commit();
}catch(Exception e) {
tx.rollback();
e.printStackTrace();
}finally {
session.close();
}

Session session1 = HibernateUtil.getInstance().getSession();
Transaction tx1 = null;
tx1 = session1.beginTransaction();
try {
session1.saveOrUpdate(customer);
tx1.commit();
}catch(Exception e) {
tx1.rollback();
e.printStackTrace();
}finally {
session1.close();
}
}


如果改为Load(customer),那么这个时候由于返回的是代理对象,那么Hibernate就一定能知道该代理对象是否被改变过,因为hibernate知道该代理对象到底有没有初始化!那么当执行saveOrUpdate()的时候不会发出update order set.......即更新orader的语句。

但是在delete操作的时候就会发现问题:

delete(customer),的时候如果customer这一端set没有设置级联,但是可以控制customer与order的关系:

Customer customer = (Customer)session.get(Customer.class, 13);
session.delete(customer);

这个时候会先发一条update order set cutomer_id=null,然后再发出delete cutomer

说明Hibernate在删除的时候会认为order集合为空存在脏数据(这句话是错误的,不是存在脏数据才update,而是因为customer必须控制关系),而customer控制了关系,因此会update order null,这与上面的案例不太符合。应该是hibernate在delete操作

的时候认为set为空的时候是改变过的吧。

但是如果:

显式的加载orders集合,Hibernate.initialize(orders);,那么这个时候删除的时候就会报错:

org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade 

其实 我觉得Hibernate是这样做的,hibernate中的perisiterset有个dirty属性,当改变set的时候会改变更新dirty为true,而此时没有改变,因此不会发出update.

在删除一个对象的时候,因为不存在级联删除,因此会报上面的错,因此删除之前必须先清除customer和order的关系才行,即cutomer.getOrders().remove(orders)

当然delete操作的原理与上面saveOrUpdate()机制是不一样的,目前只能这么想了。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息