📄 sessionfactoryutils.java
字号:
/*
* Copyright 2002-2004 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.hibernate;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.sql.DataSource;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import net.sf.hibernate.Criteria;
import net.sf.hibernate.FlushMode;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Interceptor;
import net.sf.hibernate.JDBCException;
import net.sf.hibernate.ObjectDeletedException;
import net.sf.hibernate.ObjectNotFoundException;
import net.sf.hibernate.PersistentObjectException;
import net.sf.hibernate.Query;
import net.sf.hibernate.QueryException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.StaleObjectStateException;
import net.sf.hibernate.TransientObjectException;
import net.sf.hibernate.UnresolvableObjectException;
import net.sf.hibernate.WrongClassException;
import net.sf.hibernate.connection.ConnectionProvider;
import net.sf.hibernate.engine.SessionFactoryImplementor;
import net.sf.hibernate.engine.SessionImplementor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.Ordered;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
* Helper class featuring methods for Hibernate session handling,
* allowing for reuse of Hibernate Session instances within transactions.
*
* <p>Supports synchronization with both Spring-managed JTA transactions
* (i.e. JtaTransactionManager) and non-Spring JTA transactions (i.e. plain JTA
* or EJB CMT). See the <code>getSession</code> version with all parameters
* for details.
*
* <p>Used internally by HibernateTemplate, HibernateInterceptor, and
* HibernateTransactionManager. Can also be used directly in application code,
* e.g. in combination with HibernateInterceptor.
*
* <p>Note: Spring's Hibernate support requires Hibernate 2.1 (as of Spring 1.0).
*
* @author Juergen Hoeller
* @since 02.05.2003
* @see #getSession(SessionFactory, Interceptor, SQLExceptionTranslator, boolean)
* @see HibernateTemplate
* @see HibernateInterceptor
* @see HibernateTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
public abstract class SessionFactoryUtils {
/**
* Order value for TransactionSynchronization objects that clean up Hibernate
* Sessions. Return DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100
* to execute Session cleanup before JDBC Connection cleanup, if any.
* @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
*/
public static final int SESSION_SYNCHRONIZATION_ORDER =
DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
private static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
private static ThreadLocal deferredCloseHolder = new ThreadLocal();
/**
* Determine the DataSource of the given SessionFactory.
* @param sessionFactory the SessionFactory to check
* @return the DataSource, or null if none found
* @see net.sf.hibernate.engine.SessionFactoryImplementor#getConnectionProvider
* @see LocalDataSourceConnectionProvider
*/
public static DataSource getDataSource(SessionFactory sessionFactory) {
if (sessionFactory instanceof SessionFactoryImplementor) {
ConnectionProvider cp = ((SessionFactoryImplementor) sessionFactory).getConnectionProvider();
if (cp instanceof LocalDataSourceConnectionProvider) {
return ((LocalDataSourceConnectionProvider) cp).getDataSource();
}
}
return null;
}
/**
* Create an appropriate SQLExceptionTranslator for the given SessionFactory.
* If a DataSource is found, a SQLErrorCodeSQLExceptionTranslator for the DataSource
* is created; else, a SQLStateSQLExceptionTranslator as fallback.
* @param sessionFactory the SessionFactory to create the translator for
* @return the SQLExceptionTranslator
* @see #getDataSource
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
*/
public static SQLExceptionTranslator newJdbcExceptionTranslator(SessionFactory sessionFactory) {
DataSource ds = getDataSource(sessionFactory);
if (ds != null) {
return new SQLErrorCodeSQLExceptionTranslator(ds);
}
else {
return new SQLStateSQLExceptionTranslator();
}
}
/**
* Try to retrieve the JTA TransactionManager from the given SessionFactory
* and/or Session. Check the passed-in SessionFactory for implementing
* SessionFactoryImplementor (the usual case), falling back to the
* SessionFactory reference that the Session itself carries (for example,
* when using Hibernate's JCA Connector, i.e. JCASessionFactoryImpl).
* @param sessionFactory Hibernate SessionFactory
* @param session Hibernate Session (can also be null)
* @return the JTA TransactionManager, if any
* @see javax.transaction.TransactionManager
* @see SessionFactoryImplementor#getTransactionManager
* @see Session#getSessionFactory
* @see net.sf.hibernate.impl.SessionFactoryImpl
* @see net.sf.hibernate.jca.JCASessionFactoryImpl
*/
public static TransactionManager getJtaTransactionManager(SessionFactory sessionFactory, Session session) {
SessionFactoryImplementor sessionFactoryImpl = null;
if (sessionFactory instanceof SessionFactoryImplementor) {
sessionFactoryImpl = ((SessionFactoryImplementor) sessionFactory);
}
else if (session != null) {
SessionFactory internalFactory = session.getSessionFactory();
if (internalFactory instanceof SessionFactoryImplementor) {
sessionFactoryImpl = (SessionFactoryImplementor) internalFactory;
}
}
return (sessionFactoryImpl != null ? sessionFactoryImpl.getTransactionManager() : null);
}
/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using HibernateTransactionManager. Will create a new Session
* otherwise, if allowCreate is true.
* <p>This is the <code>getSession</code> method used by typical data access code,
* in combination with <code>closeSessionIfNecessary</code> called when done with
* the Session. Note that HibernateTemplate allows to write data access code
* without caring about such resource handling.
* <p>Supports synchronization with both Spring-managed JTA transactions
* (i.e. JtaTransactionManager) and non-Spring JTA transactions (i.e. plain JTA
* or EJB CMT). See the <code>getSession</code> version with all parameters
* for details.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param allowCreate if a new Session should be created if no thread-bound found
* @return the Hibernate Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and allowCreate false
* @see #getSession(SessionFactory, Interceptor, SQLExceptionTranslator, boolean)
* @see #closeSessionIfNecessary
* @see HibernateTemplate
*/
public static Session getSession(SessionFactory sessionFactory, boolean allowCreate)
throws DataAccessResourceFailureException, IllegalStateException {
return getSession(sessionFactory, null, null, true, allowCreate);
}
/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using HibernateTransactionManager. Will always create a new
* Session otherwise.
* <p>Supports synchronization with both Spring-managed JTA transactions
* (i.e. JtaTransactionManager) and non-Spring JTA transactions (i.e. plain JTA
* or EJB CMT). See the full <code>getSession</code> version for details.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param entityInterceptor Hibernate entity interceptor, or null if none
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (can be null; only used when actually
* registering a transaction synchronization)
* @return the Hibernate Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @see #getSession(SessionFactory, Interceptor, SQLExceptionTranslator, boolean)
*/
public static Session getSession(
SessionFactory sessionFactory, Interceptor entityInterceptor,
SQLExceptionTranslator jdbcExceptionTranslator) {
return getSession(sessionFactory, entityInterceptor, jdbcExceptionTranslator, true);
}
/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using HibernateTransactionManager. Will always create a new
* Session otherwise.
* <p>Supports synchronization with Spring-managed JTA transactions
* (i.e. JtaTransactionManager) via TransactionSynchronizationManager, to allow
* for transaction-scoped Hibernate Sessions and proper transactional handling
* of the JVM-level cache. This will only occur if "allowSynchronization" is true.
* <p>Supports synchronization with non-Spring JTA transactions (i.e. plain JTA
* or EJB CMT) via TransactionSynchronizationManager, to allow for
* transaction-scoped Hibernate Sessions without JtaTransactionManager.
* This only applies when a JTA TransactionManagerLookup is specified in the
* Hibernate configuration, and when "allowSynchronization" is true.
* <p>Supports setting a Session-level Hibernate entity interceptor that allows
* to inspect and change property values before writing to and reading from the
* database. Such an interceptor can also be set at the SessionFactory level
* (i.e. on LocalSessionFactoryBean), on HibernateTransactionManager, or on
* HibernateInterceptor/HibernateTemplate.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param entityInterceptor Hibernate entity interceptor, or null if none
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (can be null; only used when actually
* registering a transaction synchronization)
* @param allowSynchronization if a new Hibernate Session is supposed to be
* registered with transaction synchronization (if synchronization is active).
* This will always be true for typical data access code.
* @return the Hibernate Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @see LocalSessionFactoryBean#setEntityInterceptor
* @see HibernateInterceptor#setEntityInterceptor
* @see HibernateTemplate#setEntityInterceptor
* @see HibernateTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
* @see org.springframework.transaction.support.TransactionSynchronizationManager
*/
public static Session getSession(
SessionFactory sessionFactory, Interceptor entityInterceptor,
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowSynchronization)
throws DataAccessResourceFailureException {
return getSession(sessionFactory, entityInterceptor, jdbcExceptionTranslator, allowSynchronization, true);
}
/**
* Get a Hibernate Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using HibernateTransactionManager. Will create a new Session
* otherwise, if allowCreate is true.
* @param sessionFactory Hibernate SessionFactory to create the session with
* @param entityInterceptor Hibernate entity interceptor, or null if none
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
* Session on transaction synchronization (can be null)
* @param allowSynchronization if a new Hibernate Session is supposed to be
* registered with transaction synchronization (if synchronization is active)
* @param allowCreate if a new Session should be created if no thread-bound found
* @return the Hibernate Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and allowCreate false
*/
private static Session getSession(
SessionFactory sessionFactory, Interceptor entityInterceptor,
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowSynchronization, boolean allowCreate)
throws DataAccessResourceFailureException, IllegalStateException {
Assert.notNull(sessionFactory, "No SessionFactory specified");
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null && !sessionHolder.isEmpty()) {
// pre-bound Hibernate Session
if (TransactionSynchronizationManager.isSynchronizationActive() &&
sessionHolder.doesNotHoldNonDefaultSession()) {
// Spring transaction management is active ->
// register pre-bound Session with it for transactional flushing.
if (allowSynchronization && !sessionHolder.isSynchronizedWithTransaction()) {
logger.debug("Registering Spring transaction synchronization for existing Hibernate session");
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.NEVER, which needs to allow flushing within the transaction.
FlushMode flushMode = sessionHolder.getSession().getFlushMode();
if (FlushMode.NEVER.equals(flushMode)) {
sessionHolder.getSession().setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
return sessionHolder.getSession();
}
else {
// No Spring transaction management active -> try JTA transaction synchronization.
Session session = getJtaSynchronizedSession(
sessionHolder, sessionFactory, jdbcExceptionTranslator, allowSynchronization);
if (session != null) {
return session;
}
}
}
if (!allowCreate) {
throw new IllegalStateException("No Hibernate session bound to thread, " +
"and configuration does not allow creation of new one here");
}
logger.debug("Opening Hibernate session");
try {
Session session = (entityInterceptor != null ?
sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());
if (allowSynchronization) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -