Browse Source

DeferredQueryInvocationHandler explicitly closes its EntityManager on garbage collection

Includes javadoc revision covering all supported EntityManager types as of JPA 2.1.

Issue: SPR-11451
pull/488/merge
Juergen Hoeller 11 years ago
parent
commit
a8577da30c
  1. 54
      spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java
  2. 43
      spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java

54
spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -44,24 +44,37 @@ import org.springframework.util.ClassUtils; @@ -44,24 +44,37 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
/**
* Factory for dynamic EntityManager proxies that follow the JPA spec's
* semantics for "extended" EntityManagers.
* Delegate for creating a variety of {@link javax.persistence.EntityManager}
* proxies that follow the JPA spec's semantics for "extended" EntityManagers.
*
* <p>Supports explicit joining of a transaction through the
* {@code joinTransaction()} method ("application-managed extended
* EntityManager") as well as automatic joining on each operation
* ("container-managed extended EntityManager").
* <p>Supports several different variants of "extended" EntityManagers:
* in particular, an "application-managed extended EntityManager", as defined
* by {@link javax.persistence.EntityManagerFactory#createEntityManager()},
* as well as a "container-managed extended EntityManager", as defined by
* {@link javax.persistence.PersistenceContextType#EXTENDED}.
*
* <p>The original difference between "application-managed" and "container-managed"
* was the need for explicit joining of an externally managed transaction through
* the {@link EntityManager#joinTransaction()} method in the "application" case
* versus the automatic joining on each user-level EntityManager operation in the
* "container" case. As of JPA 2.1, both join modes are available with both kinds of
* EntityManagers, so the difference between "application-" and "container-managed"
* is now primarily in the join mode default and in the restricted lifecycle of a
* container-managed EntityManager (i.e. tied to the object that it is injected into).
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Rod Johnson
* @since 2.0
* @see javax.persistence.EntityManagerFactory#createEntityManager()
* @see javax.persistence.PersistenceContextType#EXTENDED
* @see javax.persistence.EntityManager#joinTransaction()
* @see SharedEntityManagerCreator
*/
public abstract class ExtendedEntityManagerCreator {
/**
* Create an EntityManager that can join transactions with the {@code joinTransaction()}
* method, but is not automatically managed by the container.
* @param rawEntityManager raw EntityManager
* Create an application-managed extended EntityManager proxy.
* @param rawEntityManager the raw EntityManager to decorate
* @param emfInfo the EntityManagerFactoryInfo to obtain the JpaDialect
* and PersistenceUnitInfo from
* @return an application-managed EntityManager that can join transactions
@ -74,9 +87,8 @@ public abstract class ExtendedEntityManagerCreator { @@ -74,9 +87,8 @@ public abstract class ExtendedEntityManagerCreator {
}
/**
* Create an EntityManager that can join transactions with the {@code joinTransaction()}
* method, but is not automatically managed by the container.
* @param rawEntityManager raw EntityManager
* Create an application-managed extended EntityManager proxy.
* @param rawEntityManager the raw EntityManager to decorate
* @param emfInfo the EntityManagerFactoryInfo to obtain the JpaDialect
* and PersistenceUnitInfo from
* @param synchronizedWithTransaction whether to automatically join ongoing
@ -91,9 +103,8 @@ public abstract class ExtendedEntityManagerCreator { @@ -91,9 +103,8 @@ public abstract class ExtendedEntityManagerCreator {
}
/**
* Create an EntityManager whose lifecycle is managed by the container and which
* automatically joins a transaction when being invoked within its scope.
* @param rawEntityManager raw EntityManager
* Create a container-managed extended EntityManager proxy.
* @param rawEntityManager the raw EntityManager to decorate
* @param emfInfo the EntityManagerFactoryInfo to obtain the JpaDialect
* and PersistenceUnitInfo from
* @return a container-managed EntityManager that will automatically participate
@ -106,8 +117,7 @@ public abstract class ExtendedEntityManagerCreator { @@ -106,8 +117,7 @@ public abstract class ExtendedEntityManagerCreator {
}
/**
* Create an EntityManager whose lifecycle is managed by the container and which
* automatically joins a transaction when being invoked within its scope.
* Create a container-managed extended EntityManager proxy.
* @param emf the EntityManagerFactory to create the EntityManager with.
* If this implements the EntityManagerFactoryInfo interface, the corresponding
* JpaDialect and PersistenceUnitInfo will be detected accordingly.
@ -120,8 +130,7 @@ public abstract class ExtendedEntityManagerCreator { @@ -120,8 +130,7 @@ public abstract class ExtendedEntityManagerCreator {
}
/**
* Create an EntityManager whose lifecycle is managed by the container and which
* automatically joins a transaction when being invoked within its scope.
* Create a container-managed extended EntityManager proxy.
* @param emf the EntityManagerFactory to create the EntityManager with.
* If this implements the EntityManagerFactoryInfo interface, the corresponding
* JpaDialect and PersistenceUnitInfo will be detected accordingly.
@ -136,8 +145,7 @@ public abstract class ExtendedEntityManagerCreator { @@ -136,8 +145,7 @@ public abstract class ExtendedEntityManagerCreator {
}
/**
* Create an EntityManager whose lifecycle is managed by the container and which
* may automatically join a transaction when being invoked within its scope.
* Create a container-managed extended EntityManager proxy.
* @param emf the EntityManagerFactory to create the EntityManager with.
* If this implements the EntityManagerFactoryInfo interface, the corresponding
* JpaDialect and PersistenceUnitInfo will be detected accordingly.

43
spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,32 +24,38 @@ import java.lang.reflect.InvocationTargetException; @@ -24,32 +24,38 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
/**
* Factory for a shareable JPA {@link javax.persistence.EntityManager}
* for a given {@link javax.persistence.EntityManagerFactory}.
* Delegate for creating a shareable JPA {@link javax.persistence.EntityManager}
* reference for a given {@link javax.persistence.EntityManagerFactory}.
*
* <p>The shareable EntityManager will behave just like an EntityManager fetched
* from an application server's JNDI environment, as defined by the JPA
* specification. It will delegate all calls to the current transactional
* EntityManager, if any; otherwise it will fall back to a newly created
* EntityManager per operation.
* <p>A shared EntityManager will behave just like an EntityManager fetched from
* an application server's JNDI environment, as defined by the JPA specification.
* It will delegate all calls to the current transactional EntityManager, if any;
* otherwise it will fall back to a newly created EntityManager per operation.
*
* <p>For a behavioral definition of such a shared transactional EntityManager,
* see {@link javax.persistence.PersistenceContextType#TRANSACTION} and its
* discussion in the JPA spec document. This is also the default being used
* for the annotation-based {@link javax.persistence.PersistenceContext#type()}.
*
* @author Juergen Hoeller
* @author Rod Johnson
* @author Oliver Gierke
* @since 2.0
* @see org.springframework.orm.jpa.LocalEntityManagerFactoryBean
* @see javax.persistence.PersistenceContext
* @see javax.persistence.PersistenceContextType#TRANSACTION
* @see org.springframework.orm.jpa.JpaTransactionManager
* @see ExtendedEntityManagerCreator
*/
public abstract class SharedEntityManagerCreator {
@ -57,8 +63,7 @@ public abstract class SharedEntityManagerCreator { @@ -57,8 +63,7 @@ public abstract class SharedEntityManagerCreator {
/**
* Create a transactional EntityManager proxy for the given EntityManagerFactory,
* automatically joining ongoing transactions.
* Create a transactional EntityManager proxy for the given EntityManagerFactory.
* @param emf the EntityManagerFactory to delegate to.
* @return a shareable transaction EntityManager proxy
*/
@ -296,7 +301,7 @@ public abstract class SharedEntityManagerCreator { @@ -296,7 +301,7 @@ public abstract class SharedEntityManagerCreator {
private final Query target;
private final EntityManager em;
private EntityManager em;
public DeferredQueryInvocationHandler(Query target, EntityManager em) {
this.target = target;
@ -334,10 +339,22 @@ public abstract class SharedEntityManagerCreator { @@ -334,10 +339,22 @@ public abstract class SharedEntityManagerCreator {
finally {
if (method.getName().equals("getResultList") || method.getName().equals("getSingleResult") ||
method.getName().equals("executeUpdate")) {
// Actual execution of the query: close the EntityManager right
// afterwards, since that was the only reason we kept it open.
EntityManagerFactoryUtils.closeEntityManager(this.em);
this.em = null;
}
}
}
@Override
protected void finalize() {
// Trigger explicit EntityManager.close() call on garbage collection,
// in particular for open/close statistics to be in sync. This is
// only relevant if the Query object has not been executed, e.g.
// when just used for the early validation of query definitions.
EntityManagerFactoryUtils.closeEntityManager(this.em);
}
}
}

Loading…
Cancel
Save