All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.orm.jpa.EntityManagerFactoryUtils Maven / Gradle / Ivy

There is a newer version: 5.3.34
Show newest version
/*
 * Copyright 2002-2006 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.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.orm.jpa;

import java.util.Map;

import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityNotFoundException;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import javax.persistence.TransactionRequiredException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
 * Helper class featuring methods for JPA EntityManager handling,
 * allowing for reuse of EntityManager instances within transactions.
 * Also provides support for exception translation.
 *
 * 

Mainly intended for internal use within the framework. * * @author Juergen Hoeller * @since 2.0 */ public abstract class EntityManagerFactoryUtils { /** * Order value for TransactionSynchronization objects that clean up JPA * EntityManagers. Return DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100 * to execute EntityManager cleanup before JDBC Connection cleanup, if any. * @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER */ public static final int ENTITY_MANAGER_SYNCHRONIZATION_ORDER = DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100; private static final Log logger = LogFactory.getLog(EntityManagerFactoryUtils.class); /** * Obtain a JPA EntityManager from the given factory. Is aware of a * corresponding EntityManager bound to the current thread, * for example when using JpaTransactionManager. *

Note: Will return null if no thread-bound EntityManager found! * @param emf EntityManagerFactory to create the EntityManager with * @return the EntityManager, or null if none found * @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained * @see JpaTransactionManager */ public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf) throws DataAccessResourceFailureException { return getTransactionalEntityManager(emf, null); } /** * Obtain a JPA EntityManager from the given factory. Is aware of a * corresponding EntityManager bound to the current thread, * for example when using JpaTransactionManager. *

Note: Will return null if no thread-bound EntityManager found! * @param emf EntityManagerFactory to create the EntityManager with * @param properties the properties to be passed into the createEntityManager * call (may be null) * @return the EntityManager, or null if none found * @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained * @see JpaTransactionManager */ public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf, Map properties) throws DataAccessResourceFailureException { try { return doGetTransactionalEntityManager(emf, properties); } catch (PersistenceException ex) { throw new DataAccessResourceFailureException("Could not obtain JPA EntityManager", ex); } } /** * Obtain a JPA EntityManager from the given factory. Is aware of a * corresponding EntityManager bound to the current thread, * for example when using JpaTransactionManager. *

Same as getEntityManager, but throwing the original PersistenceException. * @param emf EntityManagerFactory to create the EntityManager with * @param properties the properties to be passed into the createEntityManager * call (may be null) * @return the EntityManager, or null if none found * @throws javax.persistence.PersistenceException if the EntityManager couldn't be created * @see #getTransactionalEntityManager(javax.persistence.EntityManagerFactory) * @see JpaTransactionManager */ public static EntityManager doGetTransactionalEntityManager( EntityManagerFactory emf, Map properties) throws PersistenceException { Assert.notNull(emf, "No EntityManagerFactory specified"); EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf); if (emHolder != null) { if (!emHolder.isSynchronizedWithTransaction() && TransactionSynchronizationManager.isSynchronizationActive()) { // Try to explicitly synchronize the EntityManager itself // with an ongoing JTA transaction, if any. try { emHolder.getEntityManager().joinTransaction(); } catch (TransactionRequiredException ex) { logger.debug("Could not join JTA transaction because none was active", ex); } emHolder.setSynchronizedWithTransaction(true); TransactionSynchronizationManager.registerSynchronization( new EntityManagerSynchronization(emHolder, emf, false)); } return emHolder.getEntityManager(); } if (!TransactionSynchronizationManager.isSynchronizationActive()) { // Indicate that we can't obtain a transactional EntityManager. return null; } // Create a new EntityManager for use within the current transaction. logger.debug("Opening JPA EntityManager"); EntityManager em = (!CollectionUtils.isEmpty(properties) ? emf.createEntityManager(properties) : emf.createEntityManager()); if (TransactionSynchronizationManager.isSynchronizationActive()) { logger.debug("Registering transaction synchronization for JPA EntityManager"); // Use same EntityManager for further JPA actions within the transaction. // Thread object will get removed by synchronization at transaction completion. emHolder = new EntityManagerHolder(em); emHolder.setSynchronizedWithTransaction(true); TransactionSynchronizationManager.registerSynchronization( new EntityManagerSynchronization(emHolder, emf, true)); TransactionSynchronizationManager.bindResource(emf, emHolder); } return em; } /** * Convert the given runtime exception to an appropriate exception from the * org.springframework.dao hierarchy. * Return null if no translation is appropriate: any other exception may * have resulted from user code, and should not be translated. *

The most important cases like object not found or optimistic locking * failure are covered here. For more fine-granular conversion, JpaAccessor and * JpaTransactionManager support sophisticated translation of exceptions via a * JpaDialect. * @param ex runtime exception that occured * @return the corresponding DataAccessException instance, * or null if the exception should not be translated */ public static DataAccessException convertJpaAccessExceptionIfPossible(RuntimeException ex) { // Following the JPA specification, a persistence provider can also // throw these two exceptions, besides PersistenceException. if (ex instanceof IllegalStateException) { return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); } if (ex instanceof IllegalArgumentException) { return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); } // Check for well-known PersistenceException subclasses. if (ex instanceof EntityNotFoundException) { return new JpaObjectRetrievalFailureException((EntityNotFoundException) ex); } if (ex instanceof NoResultException) { return new EmptyResultDataAccessException(ex.getMessage(), 1); } if (ex instanceof NonUniqueResultException) { return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1); } if (ex instanceof OptimisticLockException) { return new JpaOptimisticLockingFailureException((OptimisticLockException) ex); } if (ex instanceof EntityExistsException) { return new DataIntegrityViolationException(ex.getMessage(), ex); } if (ex instanceof TransactionRequiredException) { return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); } // If we have another kind of PersistenceException, throw it. if (ex instanceof PersistenceException) { return new JpaSystemException((PersistenceException) ex); } // If we get here, we have an exception that resulted from user code, // rather than the persistence provider, so we return null to indicate // that translation should not occur. return null; } /** * Callback for resource cleanup at the end of a non-JPA transaction * (e.g. when participating in a JtaTransactionManager transaction). * @see org.springframework.transaction.jta.JtaTransactionManager */ private static class EntityManagerSynchronization extends TransactionSynchronizationAdapter { private final EntityManagerHolder entityManagerHolder; private final EntityManagerFactory entityManagerFactory; private final boolean newEntityManager; private boolean holderActive = true; public EntityManagerSynchronization( EntityManagerHolder emHolder, EntityManagerFactory emf, boolean newEntityManager) { this.entityManagerHolder = emHolder; this.entityManagerFactory = emf; this.newEntityManager = newEntityManager; } public int getOrder() { return ENTITY_MANAGER_SYNCHRONIZATION_ORDER; } public void suspend() { if (this.holderActive) { TransactionSynchronizationManager.unbindResource(this.entityManagerFactory); } } public void resume() { if (this.holderActive) { TransactionSynchronizationManager.bindResource(this.entityManagerFactory, this.entityManagerHolder); } } public void beforeCompletion() { if (this.newEntityManager) { TransactionSynchronizationManager.unbindResource(this.entityManagerFactory); this.holderActive = false; this.entityManagerHolder.getEntityManager().close(); } } public void afterCompletion(int status) { if (!this.newEntityManager && status != STATUS_COMMITTED) { // Clear all pending inserts/updates/deletes in the EntityManager. // Necessary for pre-bound EntityManagers, to avoid inconsistent state. this.entityManagerHolder.getEntityManager().clear(); } this.entityManagerHolder.setSynchronizedWithTransaction(false); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy