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(); } }
但是在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()机制是不一样的,目前只能这么想了。。