zoukankan      html  css  js  c++  java
  • JPA(Hibernate)实体状态

    一句话总结:通过JPA(Hibernate)对实体对象进行增删改查时,JPA(Hibernate)要维护即存储对象在Session即Hibernate一级缓存中,同时还要维护其状态,具体状态变化如下图所示:

    通常我们无需关心JPA(Hibernate)的实体状态,但是碰到一些问题时需要对实体状态有所了解。

    问题一:Cannot remove detached entity异常

    通常我们会通过Spring配置自动事务,此时若在北向调用ServiceA查询出一个对象,这里查询也会有事务提交,那么这个对象其实处于detached状态,北向再调用ServiceB传递此对象进行删除,就会报错提示cannot remove detached entity异常。还有一个场景是批量提交场景,网上的示例通常在批量提交后会调用em.clear来释放内存,此时该对象也处于detached状态,再remove同样会报错。

    northbound method() {
        Object obj = service.findObject(id);
        service.removeObject(obj);  
    }
    
    service findObject method() {
        // Spring事务,自动提交commit
        return object;
    }
    
    service removeObject method(Object obj) {
        // 这里会报错
        JpaEntityManager.remove(obj);
    }

     问题二:了解实体状态后,我们知道事务自动提交后再操作对象会有detach异常,那么设计架构时就要确保每次REST请求时使用不同的Hibernate Session,若并发多次请求使用同一Session里缓存的对象,就得手动去维护对象的状态才能防止出现detach异常。

    通常我们还会使用Spring IOC,注入单例对象,这会让我们觉得Hibernate Session是同一个,如下:

    class Northbound {
        @Autowired
        Service service;
    }
    
    class Service {
        @PersistenceContext
        EntityManager em;
    }

    但其实Spring已经帮我们隐含处理了,这里有点绕,Northbound注入Service时是单例的,每次调用的是同一个service对象。但Service注入EntityManager时,却会根据每个线程即每次REST请求注入新的EntityManager(其下封装Hibernate Session)。Spring会针对PersistenceContext注解做特殊处理,将EntityManager(Session)与线程绑定,存储在ThreadLocal中。在OSGI环境中,还会使用OSGI Coordinate机制。所以用断点调试去查看,每次请求的EntityManager对象都是不同的。

    引用:

    https://docs.oracle.com/cd/E16439_01/doc.1013/e13981/undejbs003.htm

    https://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/jpa_overview_em_lifecycle.html

    https://stackoverflow.com/questions/42074270/should-there-be-an-entitymanager-per-thread-in-spring-hibernate

  • 相关阅读:
    简单记录下springboot+jms+activemq
    简单记录下RestTemplate 中postForObject调用例子
    vue+springboot后台实现页面按钮权限
    发送短信功能
    drf
    drf
    drf
    drf
    drf
    drf
  • 原文地址:https://www.cnblogs.com/yuzhengzhong/p/9785506.html
Copyright © 2011-2022 走看看