Announcement Announcement Module
Collapse
No announcement yet.
Injection of PersistenceContext with PersistenceContextType EXTENDED Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Injection of PersistenceContext with PersistenceContextType EXTENDED

    Hello everybody,

    I'm currently looking at the new JPA Support of Spring 2.0 and also would like to know, how an Entity Manager injected via @PersitenceContext works, if you use PersistenceContextType EXTENDED. (See http://forum.springframework.org/showthread.php?t=27209)

    As far as I understand, it's an container managed Entity Manager with the semantic of JPA extended entity manager.
    My main problem with this Entity Manager: how closes it? It's not closed when a tx ends because it's an extended entity manager. On the other hand it can't be closed by the application, because it's a container managed entity manager.

    Does it make sense to use PersistenceContextType EXTENDED in a purly Spring managed environment?

    Any feedback is very welcome.

    Regards
    Stefan

  • #2
    Yes it does - Extended context means that you have to take care of the transaction and the entity manager closing. While for most cases this is undesirable, such functionality makes sense in a detached environment when you might want the entity manager to live through out several requests (for example to associate a entity manager with a wizard that spans across several pages).

    Comment


    • #3
      Hello Costin,

      thank you for your quick reply. I would also say that an extended, application managed entity manager can make sence in some use cases. But one more, a bit more specific question: What happen's, if I try to use a "container managed" entity manager with Type "EXTENDED", thus injecting the entity manager with an Annotation "@PersistenceContext(..., type=PersistenceContextType.EXTENDED)". What will happen then?

      Regards
      Stefan

      Comment


      • #4
        The container will create the entity manager for you but that's about it. You'll have to start/commit the transaction yourself as well as close the entity manager.
        You can replace extended with manual - it's the non-managed type of behavior.

        Below you have some code taken from the OpenJPA documentation (I think you can find examples and more explanations in the docs from other JPA providers):
        EntityManagerFactory emf = ...
        EntityManager em = emf.createEntityManager (PersistenceContextType.EXTENDED);

        // persistence context active for entire life of EM, so only one entity
        // for a given persistent identity
        Magazine mag1 = em.find (Magazine.class, magId);
        Magazine mag2 = em.find (Magazine.class, magId);
        assertTrue (mag2 == mag1);

        em.getTransaction ().begin ();

        // same persistence context active within the transaction
        Magazine mag3 = em.find (Magazine.class, magId);
        assertTrue (mag3 == mag1);
        Magazine mag4 = em.find (Magazine.class (magId);
        assertTrue (mag4 == mag1);

        em.getTransaction.commit ();

        // when the transaction commits, instance still managed
        Magazine mag5 = em.find (Magazine.class, magId);
        assertTrue (mag5 == mag1);

        // instance finally becomes detached when EM closes
        em.close ();

        Comment


        • #5
          Dear Costin,

          in general, using an Extended Persistence Context makes sense, both on a typical rich client application in an architectural style like the one called "long running session" with hibernate or in environment which stores attached entities over more than one request/response cycle.

          But what is the semantic and usage with Spring? In the current state of RC2 an PersistenceContext of typ EXTENDED is automatically created by Spring when injected by @PersistenceContext annotation and activated by the PersistenceAnnotationBeanPostProcessor. The semantic is a "container-managed Persistence Context", so application code is not able to close the PersistenceContext, because -as bezzlebug stated- the EPC is container-managed.

          From my current point of view I noticed a semantic mismatch between application-managed and container-managed from the Spring perspective. To make myself clear: this mismatch is well founded in terms of plain JPA running within an EJB 3 compliant Java EE container. What is the understanding of container-managed in Spring environments?

          Best regards

          Comment


          • #6
            I've reviewed the spec and talked with Juergen and the situation is this:
            JPA has two types of EntityManagers - application-managed and container-managed.
            The container-managed are injected through annotations (with regard to the PersistenceContextType) while for application-managed one gets a hold of the EntityManagerFactory (EMF) either through annotations or setter/constructor injection.
            For application-managed EM, one has to retrieve the EM from the EMF and then use it as shown in my previous post.

            Comment


            • #7
              Hello Costin,

              it's me again. First of all thank you for the clarification. It's help's a lot in understanding the support for JPA that Spring has to offer. I really appreciate the the time you spend in answering all these questions!

              But one question still remains. It would be glad if you could help me on this too. The question is: Is there a szenario supported by Spring where you can use a container managed entity manager (injected by @PersistenceContext) with extended persistence context type without using a (stateful) EJB 3 session bean? If so, what kind of environment or context do you need to do this?

              So lets assume you run a Spring managed application in an non EJB enviroment, e.g. a web application in Tomcat.

              Lets assume you use LocalContainerEntityManagerFactoryBean to provide an JPA Entity Manager Factory and PersistenceAnnotationBeanPostProcessor to support the @PesistenceXxx-Annotations.

              Lets assume you have a DAO-Implementation using JPA, and you inject a JPA Entity Manager like this:

              Code:
              public class MyDaoPlainJpaImpl implements MyDaoInterface {
              
                  @PersistenceContext(type = PersistenceContextType.EXTENDED)
                  private EntityManager em;
              
                  ....
              }
              Then PersistenceAnnotationBeanPostProcessor provides the Entity Manager with this method call:

              Code:
              ExtendedEntityManagerCreator.createContainerManagedEntityManager(emf)
              which returns a proxy for the native Entity Manager provided by the Entity Manager Factory that's configured by LocalContainerEntityManagerFactoryBean.

              The invocation handler for this proxy handles a call for the method "close" like this:

              Code:
              ...
              else if (method.getName().equals("close")) {
              	if (this.containerManaged) {
              		throw new IllegalStateException("Invalid usage: Cannot close a container-managed EntityManager");
              	}
              }
              ...
              So you can not close the entity manager by yourself. That's ok, because it's a container managed entity manager.

              But on the other hand, the Transaction Synchronization Adapter, (ContainerManagedExtendedEntityManagerSynchronizat ion) provided by ExtendedEntityManagerCreator for an extended Entity Manager does not close the entity manager either:

              Code:
              ...
              public void afterCompletion(int status) {
              			this.entityManagerHolder.setSynchronizedWithTransaction(false);
              	if (status != TransactionSynchronization.STATUS_COMMITTED) {
              		this.entityManagerHolder.getEntityManager().getTransaction().rollback();
              	}
              	else {
              		this.entityManagerHolder.getEntityManager().getTransaction().commit();
              	}
              	// Don't close the EntityManager...that's up to the user
              }
              ...
              This is correct, because it's an extended entity manager.

              But the problem is that in this scenario, the entity manager isn't closed after completion of a transaction (because it's extended) and you can't close the entity manager by yourself (because it's container managed).

              So my question: Is it actually meaningfull to use "@PersistenceContext(type = PersistenceContextType.EXTENDED)" in this scenario? Or can you only use this together with a statful EJB session bean? Is there any scenario without statful EJB session beans where you can use "@PersistenceContext(type = PersistenceContextType.EXTENDED)"? (Probably with the new Feature off HTTP Session scoped Spring Beans, provided by Spring 2.0?) Or do you have to use application managed entity manager, if you need to use an extended one. (And then use it like you discribed before.)

              Regards
              Stefan

              Comment


              • #8
                I realize this is an old topic, but Stefan's question remains unanswered, What closes a container managed extended persistence context in the Spring environment?

                In an EJB environment, the persistence context is closed by the container when the @Remove method of the stateful session bean completes (or the stateful session bean instance is otherwise destroyed). How does it work in Spring?

                Comment


                • #9
                  I am using @PersistenceContext to inject an instance of EntityManager in my DAO classes. I ran into this scenario -

                  I was trying to persist a Person entity from a PersonDAO class method like

                  Code:
                  @Transactional
                  public void save(Person transientInstance) {
                  		
                  		try {           
                              entityManager.persist(transientInstance);
                              entityManager.flush();		
                  		} catch (Exception e) {
                  		
                  			throw e;
                  		}
                  	}

                  and have also configured a Hibernate Interceptor to perform audits on the Person entity. From within the interceptor I invoke AuditDAO method to fetch audit related data like

                  Code:
                      public Audit findAudit(String applicationName,
                              String entityName) {
                  
                          log.info("Finding auditable entity with application name "
                                  + applicationName + "key " + entityName);
                          Audit entity = null;
                          String queryString = "from Audit model where model."
                                  + APPLICATION + "= :applicationValue and " + KEY
                                  + "= :keyValue";
                          try {
                              
                              Query query = entityManager.createQuery(queryString);
                              query.setParameter("applicationValue", applicationName);
                              query.setParameter("keyValue", entityName);
                              entity = (Audit) query.getSingleResult();
                          } catch (Exception e) {
                             
                              throw new AuditException (e);
                          }
                  
                          if (entity != null) {        
                              log.info("Audit found for applcation name "
                                      + applicationName + "entity " + entityName);
                  
                          }
                          
                          return entity;
                      }
                  Both these DAO classes use

                  Code:
                  @PersistenceContext
                      private EntityManager entityManager = null;
                  Upon executing the code, I ran into following issues -
                  1. The AuditDAO was not able to fetch records even though it existed in the db.
                  2. The database identity for the Person class was not maintained.

                  Upon adding the attribute PersistenceContextType.EXTENDED to @PersistenceContext annotation. The problem was resolved.

                  I read in one of the articles that -

                  By default JPA provide Transaction level Persistence Context. What this means is that the Persistence Context 'lives' for the length of the transaction. If you have multiple queries using the same transaction then the same Persistence Context is used for all of those queries.
                  JPA provides 'Extended Persistence Context'. This could be thought of as the Persistence Context being 'owned' by the EntityManager rather than the Transaction. In this case the same Persistence Context can be used for multiple transactions.
                  My questions are -

                  Why did I get that error? Why was the transaction not maintained between calls across the interceptor? Does this scenario require PersistenceContextType.EXTENDED to be specified?

                  Comment


                  • #10
                    so????

                    Hello people,

                    I'm new on this forum and on Spring as well.

                    But like kott said, this question that beezlebug asked is good and remains unanswered. Does Costin Leau, Hammerstein, or anyone could give us a light??? I'm very curious about that...

                    I know that this is a really old post, but maybe someone can teach me and all the others that come by here... Spring is now on 3.1, and maybe a lot of things has changed too ...

                    Comment


                    • #11
                      This is an old post...but my 2 cents:

                      I think it was answered by Costin. I ran into this issue as well and came across this post, but for a non-web application. If you want to use extended contexts in your DAO, then you must have another object, such as that an object living in the session, that closes the context at a point in time defined by your application. In whatever object that wraps around the DAO method calls, that object would probably receive a EMF versus a EM. You would then create and close the EM base on your applications "conversation" starting and stopping. How you do this will be different for every application and every application type because its completely dependent on your application domain. For many web apps, the "conversation" is a wizard-like series of screens or a set of pages that are related together. You also see alot of the session-in-view discussion around this because that's another common, but still application dependent, scenario.

                      So if you use extended contexts in your DAOs, some other mechanism must be used to close/flush it when needed. You have to define it and its significantly more careful design work. So if your object graphs are rich with relationships that you must navigate when you want to navigate them, then you have to think more deeply about how the persistent context is used much more carefully. My domain objects have 4-5 levels of objects in them so this issue significantly affects me. In some cases, I have chosen to navigate through DAOs and not always through the object graph directly--more of a hybrid approach--that allows me to use standard transaction persistent contexts more often then not but its more confusing to clients using the code.

                      This is also why transaction tx:advice is a good answer for you in spring sometimes. Because the transaction semantics may change in different applications and you want to use the same DAOs in multiple places, it may be worth using advice configured in the spring container to set the transaction behavior on methods versus using transaction annotations which lock your transaction semantics directly into your code. In the absolute worse case, your business objects get littered with some transaction semantics but you get exactly what you want--I don't consider that wholly bad if you have something that special.


                      Originally posted by wanted.alive View Post
                      Hello people,

                      I'm new on this forum and on Spring as well.

                      But like kott said, this question that beezlebug asked is good and remains unanswered. Does Costin Leau, Hammerstein, or anyone could give us a light??? I'm very curious about that...

                      I know that this is a really old post, but maybe someone can teach me and all the others that come by here... Spring is now on 3.1, and maybe a lot of things has changed too ...

                      Comment


                      • #12
                        Any word on Stefan's observations? Does an EXTENDED container-managed persistence context ever get closed and by whom/how? 3.1.0 release code seems to be the same as Stefan's post.

                        Comment

                        Working...
                        X