刚才把hibernate升级到3.6.10,问题依旧

解决方案 »

  1.   

    这种问题据说是更新后提交不及时造成的,引用这里的话是:update update commit操作造成的。
    Course course = (Customer) postUpdateEvent.getEntity();
    你上面这句是想获得course对象吧(算符优先级有问题,假定这里没问题,只是笔误),你尝试下在每次插入Message对象的时候,执行commit操作,即让session进行flush。
    for(Customer cstm:customers){
        Message msg = new Message();
        msg.setTitle("..");
        msg.setContent("课程时间已经调整到"+course.date);
        msg.setCustomer(cstm);
        messageDAO.create(msg);
        //make sure the message is flushed by hibernate session here.
        //something like session.flush();
    }
    我猜测错误的原因应该是没有及时让hibernate把数据提交到数据库,等提交的时机到了时,却发现对象已经没法处理了。
      

  2.   

    谢谢,那个确实是笔误。刚才又反复测试,确认跟message的提交没关系,哪怕全部注释掉,只剩下:
    for(Customer cstm:customers){
       //do noting
    }
    也会报错,只要是访问到了Customer的PO就完蛋。我还测试了其他跟Course多对一关联的对象,Course是一端,可以正常运行,比如:
    Set<Teacher> teachers = course.getTeachers();
    for(Teacher tch:teachers){
       //anyting..
    }
    这让我纳闷,Teacher类和Customer类的区别在于:
    1.Customer类同时还用做Spring Security的UserDetail,但那个应该影响不到hibernate的session。
    2.Customer拥有其他的集合对象,比如Customer.getRoles(),而Teacher类只有普通的字段。从这点看来很可疑,因为collection [] was not processed by flush中,[]内就是Customer.role或者Customer其他的集合对象。但是为什么会这样?现在我在怀疑openSessionInView机制对其造成的影响,在openSessionInView中,session生命周期比事务长,用户发起request,后台调用方法对Course对象update,PostUpdateEventListener立刻捕捉到了这一操作并执行上述代码,而这时session因为openSessionInView机制而尚未关闭,但是对Course进行update操作的方法的事务已经结束。
    不知道这样会造成什么影响,如果是这个原因又如何规避。
      

  3.   

    如果确实是openSessionInView机制的原因,那么流程应该是这样:打开session——打开update方法的事务——update(course)——提交update方法的事务——触发PostUpdateEventListener——打开onPostUpdate方法的事务——重新获得course并作进一步操作——提交onPostUpdate方法的事务——报错
      

  4.   

    可以看下这里
    https://forum.hibernate.org/viewtopic.php?f=1&t=1008222
    重点这句
    The error message indicates that something is happening during the flush that causes non-initialized lazy objects to be initialized.
    是不是和customer关联的迟加载对象因为某些原因未被初始化的缘故org.hibernate.AssertionFailure: collection [???] was not processed by flush()
    这句话的意思想必也是collection没有在flush方法中被处理,因此报错
      

  5.   


    谢谢,基本可以认为是懒加载的问题,OSIV机制中,一个线程始终使用一个session,而出发hibernate监听器时,原本是应该单独使用另一个session的,结果因为OSIV强制使用一个session而导致了一些不可控制的问题。最后我把Hibernate监听器里调用的方法以多线程方式触发,解决了这个问题。
      

  6.   

    那意思就是OSIV天生不支持事件触发?因为事件多是在新的session中处理的。这个缺陷是不是太严重了
      

  7.   

    我估计监听器本身的设计目主要是输出日志,而不是进行更多的持久对象操作,只要不在监听器方法中做太复杂的持久对象操作就可以规避这个问题。但是我在考虑解决方案的时候也考虑过用切面编程的方式手动拦截相关方法,后来一想这个方案估计会遇到和Hibernate监听器一样的问题(仍然在OSIV控制的session上进行“用户请求链”之外的持久对象操作),所以没有尝试。当然这些都是我个人的猜想,没看过源码,很多问题就吃不透。
      

  8.   

    有一点可以肯定,hibernate监听器使用的session绝对就是osiv使用的那个,这个可以从控制台日志看到session的id。
      

  9.   

    我也碰到了这个问题   我的解决方法是如果使用关联对象的话 
    一定要把取到的关联对象使用之后设为null,如果需要方法传递的话  最好传递一个ID过去  然后查询出来 然后设为null 就可以了
    如果不设为null,关联的对象也会保留下来