Announcement Announcement Module
Collapse
No announcement yet.
LazyInitializationException using JPA Hibernate and LocalContainer (no web) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • LazyInitializationException using JPA Hibernate and LocalContainer (no web)

    Hello.

    I'm using JPA DAO's managed by Spring container for fetching entities that will be serialized to remote Swing clients. That means there is no web here (no conventional MVC web framework, no web controllers, no JPS's, etc... ), so I guess this is not an Open Session in View case, but I may be wrong.

    In order to force the fetching of the 'n' part in the '1-n' relationship which fetching type is 'LAZY', the code throwing the exception calls a method (size()) on the lazy fetched member (a List) of the entity. Both method call and entity retrieval are performed inside the same DAO method:

    Code:
    public class SistemaJPA implements SistemaDAO {
        @PersistenceContext
        private EntityManager em;
    
        @Override
        public Servicio getRootAndChildren() {
            //'root' is expected to be an entity instance managed by 'em'
            Servicio root = em.createNamedQuery("Servicio.raiz", Servicio.class).getSingleResult();
    
            em.isOpen(); //returns true
            em.contains(root)); //returns false! 
            
            //call list.size() for retrieving lazy 1-n relationship 
            root.getChildren().size(); //<<===== EXCEPTION HERE
            
            return raiz;
        }
    }
    Exception thrown:
    Code:
     org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.yomismamente.miapl.entidades.Servicio.children, no session or session was closed
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
    	at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122)
    	at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
    	at com.yomismamente.miapl.servicios.datos.SistemaISD.darRaizConHijos(SistemaJPA.java:16)
    	at com.yomismamente.miapl.servicios.logica.SistemaISL.cargarServicios(SistemaISL.java:15)
    	... 21 more
    The entity has a recursive 1-n relationship. I think this is not relevant to the problem except in that it excludes using 'eager' fetch type as a workaround:
    Code:
    @Entity
    @NamedQueries({
        @NamedQuery(name = "Servicio.raiz", query = "SELECT s FROM Servicio s WHERE s.categ is null")
    })
    public class Servicio implements Serializable {
        @Id
        @Column(name = "ID")
        private Integer id;
            
        @OneToMany(mappedBy = "categ")
        private List<Servicio> children;
        
        @JoinColumn(name = "CATEG", referencedColumnName = "ID")
        @ManyToOne
        private Servicio categ;
    
        //... more  ...
    
    }
    And finally the Spring configuration:
    Code:
    <bean id="jedEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="jedDataSource"/>
            <property name="persistenceUnitName" value="jed"/>
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="database" value="H2" />
                    <property name="showSql" value="true" />
                </bean>
            </property>
        </bean>
    
        <bean id="JpaTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="jedEmf"/>
        </bean>
    
        <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
    
        <bean id="sistemaJPA" class="com.yomismamente.miapl.servicios.datos.SistemaJPA"/>
    I thought that all this DAO method code would be running inside the same transaction and the same EntityManager (Hibernate Session) would be used for any operation on managed entities.

    So:
    1. How is it possible that there is 'no session (entity manager) or session was closed'?
    2. Why the entity just retrieved by the entity manager is not managed by that EM?
    3. What am I doing wrong?
    4. Is there any fix or workaround?
    5. Does this anything to to with SPR-7752 Shared EntityManager proxy does not expose JPA Provider EntityManager interface if not configured explicitly
    Please help.

    Thank you!
    Last edited by spantonio; Jun 3rd, 2011, 05:33 PM.

  • #2
    Hi spantonio,

    Do you have any transaction declaration? Try adding some transaction to your service class either configuratively via <tx:advice> or annotation via @Transactional.


    nicolas.loriente

    Comment


    • #3
      try this


      Code:
      	@PersistenceContext(type=PersistenceContextType.EXTENDED)
      	private EntityManager em;
      And also add this to your service method

      Code:
      	@Transactional

      Comment


      • #4
        Works using extended entity manager (but not recommended!)

        Thank you for your answers!

        It now works using EXTENDED entity manager. It works without using @Transactional, and actually I prefer this because one of my design requirements is keeping the code independent from Spring.

        I also have another design requirement and that is not using EJB and keeping my services stateless. I thought EXTENDED em's were to be used with stateful EJB's, which is not the case!

        So:
        • Why does it work with EXTENDED em's?
        • Is this a workaround for this case or is it the correct way to code from now onwards?
        Please let me know!

        Thanks again!
        Last edited by spantonio; Jun 6th, 2011, 01:35 PM. Reason: Remarking this workaround is not advisable

        Comment


        • #5
          @spantonio

          I would recommend NOT using an EXTENDED EntityManager unless you really understand the implications and know how to safely work with a non-shared EntityManager.

          From Spring documentation (http://static.springsource.org/sprin...m-jpa-straight):
          The @PersistenceContext annotation has an optional attribute type, which defaults to PersistenceContextType.TRANSACTION. This default is what you need to receive a shared EntityManager proxy. The alternative, PersistenceContextType.EXTENDED, is a completely different affair: This results in a so-called extended EntityManager, which is not thread-safe and hence must not be used in a concurrently accessed component such as a Spring-managed singleton bean. Extended EntityManagers are only supposed to be used in stateful components that, for example, reside in a session, with the lifecycle of the EntityManager not tied to a current transaction but rather being completely up to the application.
          If you want your code to remain decoupled from Spring you can achieve this by applying transactions declarative on Spring's context configuration via AOP using tx:advice.


          nicolas.loriente

          Comment


          • #6
            Using tx:advice is the right solution

            @nicolas.loriente

            Nicolas, thank you for your warning, after some research on EntityManager types and Spring transaction management I now understand that using EXTENDED persistence context is NOT the right option in my case, and I either recommend it in similar situations.

            As you recommended I'm using tx:advice. @Transactional also makes it work but as aforementioned I require my code to be fully decoupled from Spring. This is the config.:

            Code:
                <tx:advice id="txAdvice" transaction-manager="JpaTxManager">
                    <tx:attributes>
                        <tx:method name="*"/>
                    </tx:attributes>
                </tx:advice>
            Now please, in order to learn something about Spring let me know if this is yet a workaround or the right way to proceed. The configuration above is not instructing to behave differently from the standard behavior, so it seems to be redundant and breaking the convention over configuration principle.

            As Spring tutorial states and you have remarked:
            The @PersistenceContext annotation has an optional attribute type, which defaults to PersistenceContextType.TRANSACTION. This default is what you need to receive a shared EntityManager proxy.
            It seems that just declaring @PersistenceContext would be enough for receiving a shared EM proxy. So the question is if my original code and configuration is correct according to Spring specification or conversely I must always explicitly specify transactional configuration for my data services although that configuration is just repeating the standard behavior.

            Thank you!
            Last edited by spantonio; Jun 6th, 2011, 01:37 PM.

            Comment

            Working...
            X