Upgrade to JPA 2.1+ and Bean Validation 1.1+; remove native support for Hibernate 3.6 and 4.x
Issue: SPR-13481 Issue: SPR-13827
This commit is contained in:
@@ -1,285 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Abstract {@link org.springframework.beans.factory.FactoryBean} that creates
|
||||
* a Hibernate {@link org.hibernate.SessionFactory} within a Spring application
|
||||
* context, providing general infrastructure not related to Hibernate's
|
||||
* specific configuration API.
|
||||
*
|
||||
* <p>This class implements the
|
||||
* {@link org.springframework.dao.support.PersistenceExceptionTranslator}
|
||||
* interface, as autodetected by Spring's
|
||||
* {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
|
||||
* for AOP-based translation of native exceptions to Spring DataAccessExceptions.
|
||||
* Hence, the presence of e.g. LocalSessionFactoryBean automatically enables
|
||||
* a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions.
|
||||
*
|
||||
* <p>This class mainly serves as common base class for {@link LocalSessionFactoryBean}.
|
||||
* For details on typical SessionFactory setup, see the LocalSessionFactoryBean javadoc.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see #setExposeTransactionAwareSessionFactory
|
||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
||||
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractSessionFactoryBean extends HibernateExceptionTranslator
|
||||
implements FactoryBean<SessionFactory>, InitializingBean, DisposableBean {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
private boolean useTransactionAwareDataSource = false;
|
||||
|
||||
private boolean exposeTransactionAwareSessionFactory = true;
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the DataSource to be used by the SessionFactory.
|
||||
* If set, this will override corresponding settings in Hibernate properties.
|
||||
* <p>If this is set, the Hibernate settings should not define
|
||||
* a connection provider to avoid meaningless double configuration.
|
||||
* <p>If using HibernateTransactionManager as transaction strategy, consider
|
||||
* proxying your target DataSource with a LazyConnectionDataSourceProxy.
|
||||
* This defers fetching of an actual JDBC Connection until the first JDBC
|
||||
* Statement gets executed, even within JDBC transactions (as performed by
|
||||
* HibernateTransactionManager). Such lazy fetching is particularly beneficial
|
||||
* for read-only operations, in particular if the chances of resolving the
|
||||
* result in the second-level cache are high.
|
||||
* <p>As JTA and transactional JNDI DataSources already provide lazy enlistment
|
||||
* of JDBC Connections, LazyConnectionDataSourceProxy does not add value with
|
||||
* JTA (i.e. Spring's JtaTransactionManager) as transaction strategy.
|
||||
* @see #setUseTransactionAwareDataSource
|
||||
* @see HibernateTransactionManager
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
* @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
|
||||
*/
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataSource to be used by the SessionFactory.
|
||||
*/
|
||||
public DataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use a transaction-aware DataSource for the SessionFactory,
|
||||
* i.e. whether to automatically wrap the passed-in DataSource with Spring's
|
||||
* TransactionAwareDataSourceProxy.
|
||||
* <p>Default is "false": LocalSessionFactoryBean is usually used with Spring's
|
||||
* HibernateTransactionManager or JtaTransactionManager, both of which work nicely
|
||||
* on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are
|
||||
* fully managed by the Hibernate/JTA transaction infrastructure in such a scenario.
|
||||
* <p>If you switch this flag to "true", Spring's Hibernate access will be able to
|
||||
* <i>participate in JDBC-based transactions managed outside of Hibernate</i>
|
||||
* (for example, by Spring's DataSourceTransactionManager). This can be convenient
|
||||
* if you need a different local transaction strategy for another O/R mapping tool,
|
||||
* for example, but still want Hibernate access to join into those transactions.
|
||||
* <p>A further benefit of this option is that <i>plain Sessions opened directly
|
||||
* via the SessionFactory</i>, outside of Spring's Hibernate support, will still
|
||||
* participate in active Spring-managed transactions. However, consider using
|
||||
* Hibernate's {@code getCurrentSession()} method instead (see javadoc of
|
||||
* "exposeTransactionAwareSessionFactory" property).
|
||||
* <p><b>WARNING:</b> When using a transaction-aware JDBC DataSource in combination
|
||||
* with OpenSessionInViewFilter/Interceptor, whether participating in JTA or
|
||||
* external JDBC-based transactions, it is strongly recommended to set Hibernate's
|
||||
* Connection release mode to "after_transaction" or "after_statement", which
|
||||
* guarantees proper Connection handling in such a scenario. In contrast to that,
|
||||
* HibernateTransactionManager generally requires release mode "on_close".
|
||||
* <p>Note: If you want to use Hibernate's Connection release mode "after_statement"
|
||||
* with a DataSource specified on this LocalSessionFactoryBean (for example, a
|
||||
* JTA-aware DataSource fetched from JNDI), switch this setting to "true".
|
||||
* Otherwise, the ConnectionProvider used underneath will vote against aggressive
|
||||
* release and thus silently switch to release mode "after_transaction".
|
||||
* @see #setDataSource
|
||||
* @see #setExposeTransactionAwareSessionFactory
|
||||
* @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
|
||||
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
|
||||
* @see HibernateTransactionManager
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
*/
|
||||
public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
|
||||
this.useTransactionAwareDataSource = useTransactionAwareDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to use a transaction-aware DataSource for the SessionFactory.
|
||||
*/
|
||||
protected boolean isUseTransactionAwareDataSource() {
|
||||
return this.useTransactionAwareDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to expose a transaction-aware current Session from the
|
||||
* SessionFactory's {@code getCurrentSession()} method, returning the
|
||||
* Session that's associated with the current Spring-managed transaction, if any.
|
||||
* <p>Default is "true", letting data access code work with the plain
|
||||
* Hibernate SessionFactory and its {@code getCurrentSession()} method,
|
||||
* while still being able to participate in current Spring-managed transactions:
|
||||
* with any transaction management strategy, either local or JTA / EJB CMT,
|
||||
* and any transaction synchronization mechanism, either Spring or JTA.
|
||||
* Furthermore, {@code getCurrentSession()} will also seamlessly work with
|
||||
* a request-scoped Session managed by OpenSessionInViewFilter/Interceptor.
|
||||
* <p>Turn this flag off to expose the plain Hibernate SessionFactory with
|
||||
* Hibernate's default {@code getCurrentSession()} behavior, supporting
|
||||
* plain JTA synchronization only. Alternatively, simply override the
|
||||
* corresponding Hibernate property "hibernate.current_session_context_class".
|
||||
* @see SpringSessionContext
|
||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
* @see HibernateTransactionManager
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
|
||||
*/
|
||||
public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
|
||||
this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to expose a transaction-aware proxy for the SessionFactory.
|
||||
*/
|
||||
protected boolean isExposeTransactionAwareSessionFactory() {
|
||||
return this.exposeTransactionAwareSessionFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build and expose the SessionFactory.
|
||||
* @see #buildSessionFactory()
|
||||
* @see #wrapSessionFactoryIfNecessary
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
SessionFactory rawSf = buildSessionFactory();
|
||||
this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);
|
||||
afterSessionFactoryCreation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the given SessionFactory with a proxy, if demanded.
|
||||
* <p>The default implementation simply returns the given SessionFactory as-is.
|
||||
* Subclasses may override this to implement transaction awareness through
|
||||
* a SessionFactory proxy, for example.
|
||||
* @param rawSf the raw SessionFactory as built by {@link #buildSessionFactory()}
|
||||
* @return the SessionFactory reference to expose
|
||||
* @see #buildSessionFactory()
|
||||
*/
|
||||
protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) {
|
||||
return rawSf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the exposed SessionFactory.
|
||||
* Will throw an exception if not initialized yet.
|
||||
* @return the SessionFactory (never {@code null})
|
||||
* @throws IllegalStateException if the SessionFactory has not been initialized yet
|
||||
*/
|
||||
protected final SessionFactory getSessionFactory() {
|
||||
if (this.sessionFactory == null) {
|
||||
throw new IllegalStateException("SessionFactory not initialized yet");
|
||||
}
|
||||
return this.sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the SessionFactory on bean factory shutdown.
|
||||
*/
|
||||
@Override
|
||||
public void destroy() throws HibernateException {
|
||||
logger.info("Closing Hibernate SessionFactory");
|
||||
try {
|
||||
beforeSessionFactoryDestruction();
|
||||
}
|
||||
finally {
|
||||
this.sessionFactory.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the singleton SessionFactory.
|
||||
*/
|
||||
@Override
|
||||
public SessionFactory getObject() {
|
||||
return this.sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends SessionFactory> getObjectType() {
|
||||
return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build the underlying Hibernate SessionFactory.
|
||||
* @return the raw SessionFactory (potentially to be wrapped with a
|
||||
* transaction-aware proxy before it is exposed to the application)
|
||||
* @throws Exception in case of initialization failure
|
||||
*/
|
||||
protected abstract SessionFactory buildSessionFactory() throws Exception;
|
||||
|
||||
/**
|
||||
* Hook that allows post-processing after the SessionFactory has been
|
||||
* successfully created. The SessionFactory is already available through
|
||||
* {@code getSessionFactory()} at this point.
|
||||
* <p>This implementation is empty.
|
||||
* @throws Exception in case of initialization failure
|
||||
* @see #getSessionFactory()
|
||||
*/
|
||||
protected void afterSessionFactoryCreation() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook that allows shutdown processing before the SessionFactory
|
||||
* will be closed. The SessionFactory is still available through
|
||||
* {@code getSessionFactory()} at this point.
|
||||
* <p>This implementation is empty.
|
||||
* @see #getSessionFactory()
|
||||
*/
|
||||
protected void beforeSessionFactoryDestruction() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.hibernate3;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.FilterDefinition;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.TypeResolver;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Convenient FactoryBean for defining Hibernate FilterDefinitions.
|
||||
* Exposes a corresponding Hibernate FilterDefinition object.
|
||||
*
|
||||
* <p>Typically defined as an inner bean within a LocalSessionFactoryBean
|
||||
* definition, as the list element for the "filterDefinitions" bean property.
|
||||
* For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
|
||||
* ...
|
||||
* <property name="filterDefinitions">
|
||||
* <list>
|
||||
* <bean class="org.springframework.orm.hibernate3.FilterDefinitionFactoryBean">
|
||||
* <property name="filterName" value="myFilter"/>
|
||||
* <property name="parameterTypes">
|
||||
* <map>
|
||||
* <entry key="myParam" value="string"/>
|
||||
* <entry key="myOtherParam" value="long"/>
|
||||
* </map>
|
||||
* </property>
|
||||
* </bean>
|
||||
* </list>
|
||||
* </property>
|
||||
* ...
|
||||
* </bean></pre>
|
||||
*
|
||||
* Alternatively, specify a bean id (or name) attribute for the inner bean,
|
||||
* instead of the "filterName" property.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see org.hibernate.engine.FilterDefinition
|
||||
* @see LocalSessionFactoryBean#setFilterDefinitions
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class FilterDefinitionFactoryBean implements FactoryBean<FilterDefinition>, BeanNameAware, InitializingBean {
|
||||
|
||||
private final TypeResolver typeResolver = new TypeResolver();
|
||||
|
||||
private String filterName;
|
||||
|
||||
private Map<String, Type> parameterTypeMap = new HashMap<String, Type>();
|
||||
|
||||
private String defaultFilterCondition;
|
||||
|
||||
private FilterDefinition filterDefinition;
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the filter.
|
||||
*/
|
||||
public void setFilterName(String filterName) {
|
||||
this.filterName = filterName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameter types for the filter,
|
||||
* with parameter names as keys and type names as values.
|
||||
* See {@code org.hibernate.type.TypeResolver#heuristicType(String)}.
|
||||
*/
|
||||
public void setParameterTypes(Map<String, String> parameterTypes) {
|
||||
if (parameterTypes != null) {
|
||||
this.parameterTypeMap = new HashMap<String, Type>(parameterTypes.size());
|
||||
for (Map.Entry<String, String> entry : parameterTypes.entrySet()) {
|
||||
this.parameterTypeMap.put(entry.getKey(), this.typeResolver.heuristicType(entry.getValue()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.parameterTypeMap = new HashMap<String, Type>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a default filter condition for the filter, if any.
|
||||
*/
|
||||
public void setDefaultFilterCondition(String defaultFilterCondition) {
|
||||
this.defaultFilterCondition = defaultFilterCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* If no explicit filter name has been specified, the bean name of
|
||||
* the FilterDefinitionFactoryBean will be used.
|
||||
* @see #setFilterName
|
||||
*/
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
if (this.filterName == null) {
|
||||
this.filterName = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
this.filterDefinition =
|
||||
new FilterDefinition(this.filterName, this.defaultFilterCondition, this.parameterTypeMap);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FilterDefinition getObject() {
|
||||
return this.filterDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<FilterDefinition> getObjectType() {
|
||||
return FilterDefinition.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,492 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.hibernate3;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.exception.GenericJDBCException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.Constants;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
||||
|
||||
/**
|
||||
* Base class for {@link HibernateTemplate} and {@link HibernateInterceptor},
|
||||
* defining common properties such as SessionFactory and flushing behavior.
|
||||
*
|
||||
* <p>Not intended to be used directly.
|
||||
* See {@link HibernateTemplate} and {@link HibernateInterceptor}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see HibernateTemplate
|
||||
* @see HibernateInterceptor
|
||||
* @see #setFlushMode
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class HibernateAccessor implements InitializingBean, BeanFactoryAware {
|
||||
|
||||
/**
|
||||
* Never flush is a good strategy for read-only units of work.
|
||||
* Hibernate will not track and look for changes in this case,
|
||||
* avoiding any overhead of modification detection.
|
||||
* <p>In case of an existing Session, FLUSH_NEVER will turn the flush mode
|
||||
* to NEVER for the scope of the current operation, resetting the previous
|
||||
* flush mode afterwards.
|
||||
* @see #setFlushMode
|
||||
*/
|
||||
public static final int FLUSH_NEVER = 0;
|
||||
|
||||
/**
|
||||
* Automatic flushing is the default mode for a Hibernate Session.
|
||||
* A session will get flushed on transaction commit, and on certain find
|
||||
* operations that might involve already modified instances, but not
|
||||
* after each unit of work like with eager flushing.
|
||||
* <p>In case of an existing Session, FLUSH_AUTO will participate in the
|
||||
* existing flush mode, not modifying it for the current operation.
|
||||
* This in particular means that this setting will not modify an existing
|
||||
* flush mode NEVER, in contrast to FLUSH_EAGER.
|
||||
* @see #setFlushMode
|
||||
*/
|
||||
public static final int FLUSH_AUTO = 1;
|
||||
|
||||
/**
|
||||
* Eager flushing leads to immediate synchronization with the database,
|
||||
* even if in a transaction. This causes inconsistencies to show up and throw
|
||||
* a respective exception immediately, and JDBC access code that participates
|
||||
* in the same transaction will see the changes as the database is already
|
||||
* aware of them then. But the drawbacks are:
|
||||
* <ul>
|
||||
* <li>additional communication roundtrips with the database, instead of a
|
||||
* single batch at transaction commit;
|
||||
* <li>the fact that an actual database rollback is needed if the Hibernate
|
||||
* transaction rolls back (due to already submitted SQL statements).
|
||||
* </ul>
|
||||
* <p>In case of an existing Session, FLUSH_EAGER will turn the flush mode
|
||||
* to AUTO for the scope of the current operation and issue a flush at the
|
||||
* end, resetting the previous flush mode afterwards.
|
||||
* @see #setFlushMode
|
||||
*/
|
||||
public static final int FLUSH_EAGER = 2;
|
||||
|
||||
/**
|
||||
* Flushing at commit only is intended for units of work where no
|
||||
* intermediate flushing is desired, not even for find operations
|
||||
* that might involve already modified instances.
|
||||
* <p>In case of an existing Session, FLUSH_COMMIT will turn the flush mode
|
||||
* to COMMIT for the scope of the current operation, resetting the previous
|
||||
* flush mode afterwards. The only exception is an existing flush mode
|
||||
* NEVER, which will not be modified through this setting.
|
||||
* @see #setFlushMode
|
||||
*/
|
||||
public static final int FLUSH_COMMIT = 3;
|
||||
|
||||
/**
|
||||
* Flushing before every query statement is rarely necessary.
|
||||
* It is only available for special needs.
|
||||
* <p>In case of an existing Session, FLUSH_ALWAYS will turn the flush mode
|
||||
* to ALWAYS for the scope of the current operation, resetting the previous
|
||||
* flush mode afterwards.
|
||||
* @see #setFlushMode
|
||||
*/
|
||||
public static final int FLUSH_ALWAYS = 4;
|
||||
|
||||
|
||||
/** Constants instance for HibernateAccessor */
|
||||
private static final Constants constants = new Constants(HibernateAccessor.class);
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private Object entityInterceptor;
|
||||
|
||||
private SQLExceptionTranslator jdbcExceptionTranslator;
|
||||
|
||||
private SQLExceptionTranslator defaultJdbcExceptionTranslator;
|
||||
|
||||
private int flushMode = FLUSH_AUTO;
|
||||
|
||||
private String[] filterNames;
|
||||
|
||||
/**
|
||||
* Just needed for entityInterceptorBeanName.
|
||||
* @see #setEntityInterceptorBeanName
|
||||
*/
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the Hibernate SessionFactory that should be used to create
|
||||
* Hibernate Sessions.
|
||||
*/
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Hibernate SessionFactory that should be used to create
|
||||
* Hibernate Sessions.
|
||||
*/
|
||||
public SessionFactory getSessionFactory() {
|
||||
return this.sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean name of a Hibernate entity interceptor that allows to inspect
|
||||
* and change property values before writing to and reading from the database.
|
||||
* Will get applied to any new Session created by this transaction manager.
|
||||
* <p>Requires the bean factory to be known, to be able to resolve the bean
|
||||
* name to an interceptor instance on session creation. Typically used for
|
||||
* prototype interceptors, i.e. a new interceptor instance per session.
|
||||
* <p>Can also be used for shared interceptor instances, but it is recommended
|
||||
* to set the interceptor reference directly in such a scenario.
|
||||
* @param entityInterceptorBeanName the name of the entity interceptor in
|
||||
* the bean factory
|
||||
* @see #setBeanFactory
|
||||
* @see #setEntityInterceptor
|
||||
*/
|
||||
public void setEntityInterceptorBeanName(String entityInterceptorBeanName) {
|
||||
this.entityInterceptor = entityInterceptorBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Hibernate entity interceptor that allows to inspect and change
|
||||
* property values before writing to and reading from the database.
|
||||
* Will get applied to any <b>new</b> Session created by this object.
|
||||
* <p>Such an interceptor can either be set at the SessionFactory level,
|
||||
* i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
|
||||
* HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
|
||||
* It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
|
||||
* to avoid repeated configuration and guarantee consistent behavior in transactions.
|
||||
* @see #setEntityInterceptorBeanName
|
||||
* @see LocalSessionFactoryBean#setEntityInterceptor
|
||||
* @see HibernateTransactionManager#setEntityInterceptor
|
||||
*/
|
||||
public void setEntityInterceptor(Interceptor entityInterceptor) {
|
||||
this.entityInterceptor = entityInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current Hibernate entity interceptor, or {@code null} if none.
|
||||
* Resolves an entity interceptor bean name via the bean factory,
|
||||
* if necessary.
|
||||
* @throws IllegalStateException if bean name specified but no bean factory set
|
||||
* @throws org.springframework.beans.BeansException if bean name resolution via the bean factory failed
|
||||
* @see #setEntityInterceptor
|
||||
* @see #setEntityInterceptorBeanName
|
||||
* @see #setBeanFactory
|
||||
*/
|
||||
public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
|
||||
if (this.entityInterceptor instanceof String) {
|
||||
if (this.beanFactory == null) {
|
||||
throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
|
||||
}
|
||||
return this.beanFactory.getBean((String) this.entityInterceptor, Interceptor.class);
|
||||
}
|
||||
return (Interceptor) this.entityInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JDBC exception translator for this instance.
|
||||
* <p>Applied to any SQLException root cause of a Hibernate JDBCException,
|
||||
* overriding Hibernate's default SQLException translation (which is
|
||||
* based on Hibernate's Dialect for a specific target database).
|
||||
* @param jdbcExceptionTranslator the exception translator
|
||||
* @see java.sql.SQLException
|
||||
* @see org.hibernate.JDBCException
|
||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
|
||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
|
||||
*/
|
||||
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
|
||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JDBC exception translator for this instance, if any.
|
||||
*/
|
||||
public SQLExceptionTranslator getJdbcExceptionTranslator() {
|
||||
return this.jdbcExceptionTranslator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flush behavior by the name of the respective constant
|
||||
* in this class, e.g. "FLUSH_AUTO". Default is "FLUSH_AUTO".
|
||||
* @param constantName name of the constant
|
||||
* @see #setFlushMode
|
||||
* @see #FLUSH_AUTO
|
||||
*/
|
||||
public void setFlushModeName(String constantName) {
|
||||
setFlushMode(constants.asNumber(constantName).intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flush behavior to one of the constants in this class.
|
||||
* Default is FLUSH_AUTO.
|
||||
* @see #setFlushModeName
|
||||
* @see #FLUSH_AUTO
|
||||
*/
|
||||
public void setFlushMode(int flushMode) {
|
||||
this.flushMode = flushMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if a flush should be forced after executing the callback code.
|
||||
*/
|
||||
public int getFlushMode() {
|
||||
return this.flushMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of a Hibernate filter to be activated for all
|
||||
* Sessions that this accessor works with.
|
||||
* <p>This filter will be enabled at the beginning of each operation
|
||||
* and correspondingly disabled at the end of the operation.
|
||||
* This will work for newly opened Sessions as well as for existing
|
||||
* Sessions (for example, within a transaction).
|
||||
* @see #enableFilters(org.hibernate.Session)
|
||||
* @see org.hibernate.Session#enableFilter(String)
|
||||
* @see LocalSessionFactoryBean#setFilterDefinitions
|
||||
*/
|
||||
public void setFilterName(String filter) {
|
||||
this.filterNames = new String[] {filter};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one or more names of Hibernate filters to be activated for all
|
||||
* Sessions that this accessor works with.
|
||||
* <p>Each of those filters will be enabled at the beginning of each
|
||||
* operation and correspondingly disabled at the end of the operation.
|
||||
* This will work for newly opened Sessions as well as for existing
|
||||
* Sessions (for example, within a transaction).
|
||||
* @see #enableFilters(org.hibernate.Session)
|
||||
* @see org.hibernate.Session#enableFilter(String)
|
||||
* @see LocalSessionFactoryBean#setFilterDefinitions
|
||||
*/
|
||||
public void setFilterNames(String... filterNames) {
|
||||
this.filterNames = filterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of Hibernate filters to be activated, if any.
|
||||
*/
|
||||
public String[] getFilterNames() {
|
||||
return this.filterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bean factory just needs to be known for resolving entity interceptor
|
||||
* bean names. It does not need to be set for any other mode of operation.
|
||||
* @see #setEntityInterceptorBeanName
|
||||
*/
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (getSessionFactory() == null) {
|
||||
throw new IllegalArgumentException("Property 'sessionFactory' is required");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Apply the flush mode that's been specified for this accessor
|
||||
* to the given Session.
|
||||
* @param session the current Hibernate Session
|
||||
* @param existingTransaction if executing within an existing transaction
|
||||
* @return the previous flush mode to restore after the operation,
|
||||
* or {@code null} if none
|
||||
* @see #setFlushMode
|
||||
* @see org.hibernate.Session#setFlushMode
|
||||
*/
|
||||
protected FlushMode applyFlushMode(Session session, boolean existingTransaction) {
|
||||
if (getFlushMode() == FLUSH_NEVER) {
|
||||
if (existingTransaction) {
|
||||
FlushMode previousFlushMode = session.getFlushMode();
|
||||
if (!previousFlushMode.lessThan(FlushMode.COMMIT)) {
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
return previousFlushMode;
|
||||
}
|
||||
}
|
||||
else {
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
}
|
||||
}
|
||||
else if (getFlushMode() == FLUSH_EAGER) {
|
||||
if (existingTransaction) {
|
||||
FlushMode previousFlushMode = session.getFlushMode();
|
||||
if (!previousFlushMode.equals(FlushMode.AUTO)) {
|
||||
session.setFlushMode(FlushMode.AUTO);
|
||||
return previousFlushMode;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// rely on default FlushMode.AUTO
|
||||
}
|
||||
}
|
||||
else if (getFlushMode() == FLUSH_COMMIT) {
|
||||
if (existingTransaction) {
|
||||
FlushMode previousFlushMode = session.getFlushMode();
|
||||
if (previousFlushMode.equals(FlushMode.AUTO) || previousFlushMode.equals(FlushMode.ALWAYS)) {
|
||||
session.setFlushMode(FlushMode.COMMIT);
|
||||
return previousFlushMode;
|
||||
}
|
||||
}
|
||||
else {
|
||||
session.setFlushMode(FlushMode.COMMIT);
|
||||
}
|
||||
}
|
||||
else if (getFlushMode() == FLUSH_ALWAYS) {
|
||||
if (existingTransaction) {
|
||||
FlushMode previousFlushMode = session.getFlushMode();
|
||||
if (!previousFlushMode.equals(FlushMode.ALWAYS)) {
|
||||
session.setFlushMode(FlushMode.ALWAYS);
|
||||
return previousFlushMode;
|
||||
}
|
||||
}
|
||||
else {
|
||||
session.setFlushMode(FlushMode.ALWAYS);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the given Hibernate Session if necessary.
|
||||
* @param session the current Hibernate Session
|
||||
* @param existingTransaction if executing within an existing transaction
|
||||
* @throws HibernateException in case of Hibernate flushing errors
|
||||
*/
|
||||
protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {
|
||||
if (getFlushMode() == FLUSH_EAGER || (!existingTransaction && getFlushMode() != FLUSH_NEVER)) {
|
||||
logger.debug("Eagerly flushing Hibernate session");
|
||||
session.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the given HibernateException to an appropriate exception
|
||||
* from the {@code org.springframework.dao} hierarchy.
|
||||
* <p>Will automatically apply a specified SQLExceptionTranslator to a
|
||||
* Hibernate JDBCException, else rely on Hibernate's default translation.
|
||||
* @param ex HibernateException that occured
|
||||
* @return a corresponding DataAccessException
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
||||
* @see #setJdbcExceptionTranslator
|
||||
*/
|
||||
public DataAccessException convertHibernateAccessException(HibernateException ex) {
|
||||
if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
|
||||
return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
|
||||
}
|
||||
else if (GenericJDBCException.class == ex.getClass()) {
|
||||
return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator());
|
||||
}
|
||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given Hibernate JDBCException to an appropriate exception
|
||||
* from the {@code org.springframework.dao} hierarchy, using the
|
||||
* given SQLExceptionTranslator.
|
||||
* @param ex Hibernate JDBCException that occured
|
||||
* @param translator the SQLExceptionTranslator to use
|
||||
* @return a corresponding DataAccessException
|
||||
*/
|
||||
protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) {
|
||||
return translator.translate("Hibernate operation: " + ex.getMessage(), ex.getSQL(), ex.getSQLException());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given SQLException to an appropriate exception from the
|
||||
* {@code org.springframework.dao} hierarchy. Can be overridden in subclasses.
|
||||
* <p>Note that a direct SQLException can just occur when callback code
|
||||
* performs direct JDBC access via {@code Session.connection()}.
|
||||
* @param ex the SQLException
|
||||
* @return the corresponding DataAccessException instance
|
||||
* @see #setJdbcExceptionTranslator
|
||||
*/
|
||||
protected DataAccessException convertJdbcAccessException(SQLException ex) {
|
||||
SQLExceptionTranslator translator = getJdbcExceptionTranslator();
|
||||
if (translator == null) {
|
||||
translator = getDefaultJdbcExceptionTranslator();
|
||||
}
|
||||
return translator.translate("Hibernate-related JDBC operation", null, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a default SQLExceptionTranslator, lazily creating it if necessary.
|
||||
* <p>Creates a default
|
||||
* {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator}
|
||||
* for the SessionFactory's underlying DataSource.
|
||||
*/
|
||||
protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() {
|
||||
if (this.defaultJdbcExceptionTranslator == null) {
|
||||
this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory());
|
||||
}
|
||||
return this.defaultJdbcExceptionTranslator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable the specified filters on the given Session.
|
||||
* @param session the current Hibernate Session
|
||||
* @see #setFilterNames
|
||||
* @see org.hibernate.Session#enableFilter(String)
|
||||
*/
|
||||
protected void enableFilters(Session session) {
|
||||
String[] filterNames = getFilterNames();
|
||||
if (filterNames != null) {
|
||||
for (String filterName : filterNames) {
|
||||
session.enableFilter(filterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the specified filters on the given Session.
|
||||
* @param session the current Hibernate Session
|
||||
* @see #setFilterNames
|
||||
* @see org.hibernate.Session#disableFilter(String)
|
||||
*/
|
||||
protected void disableFilters(Session session) {
|
||||
String[] filterNames = getFilterNames();
|
||||
if (filterNames != null) {
|
||||
for (String filterName : filterNames) {
|
||||
session.disableFilter(filterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.hibernate3;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* This interceptor binds a new Hibernate Session to the thread before a method
|
||||
* call, closing and removing it afterwards in case of any method outcome.
|
||||
* If there already is a pre-bound Session (e.g. from HibernateTransactionManager,
|
||||
* or from a surrounding Hibernate-intercepted method), the interceptor simply
|
||||
* participates in it.
|
||||
*
|
||||
* <p>Application code must retrieve a Hibernate Session via the
|
||||
* {@code SessionFactoryUtils.getSession} method or - preferably -
|
||||
* Hibernate's own {@code SessionFactory.getCurrentSession()} method, to be
|
||||
* able to detect a thread-bound Session. Typically, the code will look like as follows:
|
||||
*
|
||||
* <pre class="code">
|
||||
* public void doSomeDataAccessAction() {
|
||||
* Session session = this.sessionFactory.getCurrentSession();
|
||||
* ...
|
||||
* // No need to close the Session or translate exceptions!
|
||||
* }</pre>
|
||||
*
|
||||
* Note that this interceptor automatically translates HibernateExceptions,
|
||||
* via delegating to the {@code SessionFactoryUtils.convertHibernateAccessException}
|
||||
* method that converts them to exceptions that are compatible with the
|
||||
* {@code org.springframework.dao} exception hierarchy (like HibernateTemplate does).
|
||||
* This can be turned off if the raw exceptions are preferred.
|
||||
*
|
||||
* <p>This class can be considered a declarative alternative to HibernateTemplate's
|
||||
* callback approach. The advantages are:
|
||||
* <ul>
|
||||
* <li>no anonymous classes necessary for callback implementations;
|
||||
* <li>the possibility to throw any application exceptions from within data access code.
|
||||
* </ul>
|
||||
*
|
||||
* <p>The drawback is the dependency on interceptor configuration. However, note
|
||||
* that this interceptor is usually <i>not</i> necessary in scenarios where the
|
||||
* data access code always executes within transactions. A transaction will always
|
||||
* have a thread-bound Session in the first place, so adding this interceptor to the
|
||||
* configuration just adds value when fine-tuning Session settings like the flush mode
|
||||
* - or when relying on exception translation.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
||||
* @see HibernateTransactionManager
|
||||
* @see HibernateTemplate
|
||||
* @deprecated as of Spring 3.2.7, in favor of either HibernateTemplate usage or
|
||||
* native Hibernate API usage within transactions, in combination with a general
|
||||
* {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor}.
|
||||
* Note: This class does not have an equivalent replacement in {@code orm.hibernate4}.
|
||||
* If you desperately need a scoped Session bound through AOP, consider the newly
|
||||
* introduced {@link org.springframework.orm.hibernate3.support.OpenSessionInterceptor}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class HibernateInterceptor extends HibernateAccessor implements MethodInterceptor {
|
||||
|
||||
private boolean exceptionConversionEnabled = true;
|
||||
|
||||
|
||||
/**
|
||||
* Set whether to convert any HibernateException raised to a Spring DataAccessException,
|
||||
* compatible with the {@code org.springframework.dao} exception hierarchy.
|
||||
* <p>Default is "true". Turn this flag off to let the caller receive raw exceptions
|
||||
* as-is, without any wrapping.
|
||||
* @see org.springframework.dao.DataAccessException
|
||||
*/
|
||||
public void setExceptionConversionEnabled(boolean exceptionConversionEnabled) {
|
||||
this.exceptionConversionEnabled = exceptionConversionEnabled;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
|
||||
Session session = getSession();
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
||||
|
||||
boolean existingTransaction = (sessionHolder != null && sessionHolder.containsSession(session));
|
||||
if (existingTransaction) {
|
||||
logger.debug("Found thread-bound Session for HibernateInterceptor");
|
||||
}
|
||||
else {
|
||||
if (sessionHolder != null) {
|
||||
sessionHolder.addSession(session);
|
||||
}
|
||||
else {
|
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
|
||||
}
|
||||
}
|
||||
|
||||
FlushMode previousFlushMode = null;
|
||||
try {
|
||||
previousFlushMode = applyFlushMode(session, existingTransaction);
|
||||
enableFilters(session);
|
||||
Object retVal = methodInvocation.proceed();
|
||||
flushIfNecessary(session, existingTransaction);
|
||||
return retVal;
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
if (this.exceptionConversionEnabled) {
|
||||
throw convertHibernateAccessException(ex);
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (existingTransaction) {
|
||||
logger.debug("Not closing pre-bound Hibernate Session after HibernateInterceptor");
|
||||
disableFilters(session);
|
||||
if (previousFlushMode != null) {
|
||||
session.setFlushMode(previousFlushMode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
|
||||
if (sessionHolder == null || sessionHolder.doesNotHoldNonDefaultSession()) {
|
||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Session for use by this interceptor.
|
||||
* @see SessionFactoryUtils#getSession
|
||||
*/
|
||||
protected Session getSession() {
|
||||
return SessionFactoryUtils.getSession(
|
||||
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.connection.ConnectionProvider;
|
||||
import org.hibernate.util.JDBCExceptionReporter;
|
||||
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
|
||||
/**
|
||||
* Hibernate connection provider for local DataSource instances
|
||||
* in an application context. This provider will be used if
|
||||
* LocalSessionFactoryBean's "dataSource" property is set
|
||||
* without a Hibernate TransactionManagerLookup.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see LocalSessionFactoryBean#setDataSource
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class LocalDataSourceConnectionProvider implements ConnectionProvider {
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
private DataSource dataSourceToUse;
|
||||
|
||||
|
||||
@Override
|
||||
public void configure(Properties props) throws HibernateException {
|
||||
this.dataSource = LocalSessionFactoryBean.getConfigTimeDataSource();
|
||||
// absolutely needs thread-bound DataSource to initialize
|
||||
if (this.dataSource == null) {
|
||||
throw new HibernateException("No local DataSource found for configuration - " +
|
||||
"'dataSource' property must be set on LocalSessionFactoryBean");
|
||||
}
|
||||
this.dataSourceToUse = getDataSourceToUse(this.dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataSource to use for retrieving Connections.
|
||||
* <p>This implementation returns the passed-in DataSource as-is.
|
||||
* @param originalDataSource the DataSource as configured by the user
|
||||
* on LocalSessionFactoryBean
|
||||
* @return the DataSource to actually retrieve Connections from
|
||||
* (potentially wrapped)
|
||||
* @see LocalSessionFactoryBean#setDataSource
|
||||
*/
|
||||
protected DataSource getDataSourceToUse(DataSource originalDataSource) {
|
||||
return originalDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataSource that this ConnectionProvider wraps.
|
||||
*/
|
||||
public DataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to the underlying DataSource.
|
||||
* @see javax.sql.DataSource#getConnection()
|
||||
*/
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
try {
|
||||
return this.dataSourceToUse.getConnection();
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
JDBCExceptionReporter.logExceptions(ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation calls {@link DataSourceUtils#doCloseConnection},
|
||||
* checking against a {@link org.springframework.jdbc.datasource.SmartDataSource}.
|
||||
*/
|
||||
@Override
|
||||
public void closeConnection(Connection con) throws SQLException {
|
||||
try {
|
||||
DataSourceUtils.doCloseConnection(con, this.dataSourceToUse);
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
JDBCExceptionReporter.logExceptions(ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation does nothing:
|
||||
* We're dealing with an externally managed DataSource.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns {@code false}: We cannot guarantee
|
||||
* to receive the same Connection within a transaction, not even when
|
||||
* dealing with a JNDI DataSource.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsAggressiveRelease() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
/**
|
||||
* Subclass of LocalDataSourceConnectionProvider that will be used
|
||||
* if LocalSessionFactoryBean's "dataSource" property is set
|
||||
* in combination with a Hibernate TransactionManagerLookup.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.1
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class LocalJtaDataSourceConnectionProvider extends LocalDataSourceConnectionProvider {
|
||||
|
||||
/**
|
||||
* This implementation returns {@code true},
|
||||
* since we're assuming a JTA DataSource.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsAggressiveRelease() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.hibernate3;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.CollectionRegion;
|
||||
import org.hibernate.cache.EntityRegion;
|
||||
import org.hibernate.cache.QueryResultsRegion;
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cache.TimestampsRegion;
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
||||
/**
|
||||
* Proxy for a Hibernate RegionFactory, delegating to a Spring-managed
|
||||
* RegionFactory instance, determined by LocalSessionFactoryBean's
|
||||
* "cacheRegionFactory" property.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see LocalSessionFactoryBean#setCacheRegionFactory
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class LocalRegionFactoryProxy implements RegionFactory {
|
||||
|
||||
private final RegionFactory regionFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Standard constructor.
|
||||
*/
|
||||
public LocalRegionFactoryProxy() {
|
||||
RegionFactory rf = (RegionFactory) LocalSessionFactoryBean.getConfigTimeRegionFactory();
|
||||
// absolutely needs thread-bound RegionFactory to initialize
|
||||
if (rf == null) {
|
||||
throw new IllegalStateException("No Hibernate RegionFactory found - " +
|
||||
"'cacheRegionFactory' property must be set on LocalSessionFactoryBean");
|
||||
}
|
||||
this.regionFactory = rf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties constructor: not used by this class or formally required,
|
||||
* but enforced by Hibernate when reflectively instantiating a RegionFactory.
|
||||
*/
|
||||
public LocalRegionFactoryProxy(Properties properties) {
|
||||
this();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start(Settings settings, Properties properties) throws CacheException {
|
||||
this.regionFactory.start(settings, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
this.regionFactory.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMinimalPutsEnabledByDefault() {
|
||||
return this.regionFactory.isMinimalPutsEnabledByDefault();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessType getDefaultAccessType() {
|
||||
return this.regionFactory.getDefaultAccessType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextTimestamp() {
|
||||
return this.regionFactory.nextTimestamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
|
||||
throws CacheException {
|
||||
|
||||
return this.regionFactory.buildEntityRegion(regionName, properties, metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionRegion buildCollectionRegion(String regionName, Properties properties,
|
||||
CacheDataDescription metadata) throws CacheException {
|
||||
|
||||
return this.regionFactory.buildCollectionRegion(regionName, properties, metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties)
|
||||
throws CacheException {
|
||||
|
||||
return this.regionFactory.buildQueryResultsRegion(regionName, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties)
|
||||
throws CacheException {
|
||||
|
||||
return this.regionFactory.buildTimestampsRegion(regionName, properties);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
import java.util.Properties;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.hibernate.transaction.TransactionManagerLookup;
|
||||
|
||||
/**
|
||||
* Implementation of Hibernate's {@link TransactionManagerLookup} interface
|
||||
* that returns a Spring-managed JTA {@link TransactionManager}, determined
|
||||
* by LocalSessionFactoryBean's "jtaTransactionManager" property.
|
||||
*
|
||||
* <p>The main advantage of this TransactionManagerLookup is that it avoids
|
||||
* double configuration of JTA specifics. A single TransactionManager bean can
|
||||
* be used for both JtaTransactionManager and LocalSessionFactoryBean, with no
|
||||
* JTA setup in Hibernate configuration.
|
||||
*
|
||||
* <p>Alternatively, use Hibernate's own TransactionManagerLookup implementations:
|
||||
* Spring's JtaTransactionManager only requires a TransactionManager for suspending
|
||||
* and resuming transactions, so you might not need to apply such special Spring
|
||||
* configuration at all.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see LocalSessionFactoryBean#setJtaTransactionManager
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class LocalTransactionManagerLookup implements TransactionManagerLookup {
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
|
||||
public LocalTransactionManagerLookup() {
|
||||
TransactionManager tm = LocalSessionFactoryBean.getConfigTimeTransactionManager();
|
||||
// absolutely needs thread-bound TransactionManager to initialize
|
||||
if (tm == null) {
|
||||
throw new IllegalStateException("No JTA TransactionManager found - " +
|
||||
"'jtaTransactionManager' property must be set on LocalSessionFactoryBean");
|
||||
}
|
||||
this.transactionManager = tm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionManager getTransactionManager(Properties props) {
|
||||
return this.transactionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserTransactionName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTransactionIdentifier(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,832 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.hibernate3;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.sql.DataSource;
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.NonUniqueObjectException;
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
import org.hibernate.ObjectDeletedException;
|
||||
import org.hibernate.OptimisticLockException;
|
||||
import org.hibernate.PersistentObjectException;
|
||||
import org.hibernate.PessimisticLockException;
|
||||
import org.hibernate.PropertyValueException;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.QueryTimeoutException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.connection.ConnectionProvider;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.exception.DataException;
|
||||
import org.hibernate.exception.JDBCConnectionException;
|
||||
import org.hibernate.exception.LockAcquisitionException;
|
||||
import org.hibernate.exception.SQLGrammarException;
|
||||
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
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.jta.SpringJtaSynchronizationAdapter;
|
||||
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.
|
||||
* Also provides support for exception translation.
|
||||
*
|
||||
* <p>Supports synchronization with both Spring-managed JTA transactions
|
||||
* (see {@link org.springframework.transaction.jta.JtaTransactionManager})
|
||||
* and non-Spring JTA transactions (i.e. plain JTA or EJB CMT),
|
||||
* transparently providing transaction-scoped Hibernate Sessions.
|
||||
* Note that for non-Spring JTA transactions, a JTA TransactionManagerLookup
|
||||
* has to be specified in the Hibernate configuration.
|
||||
*
|
||||
* <p>Used internally by {@link HibernateTemplate}, {@link HibernateInterceptor}
|
||||
* and {@link HibernateTransactionManager}. Can also be used directly in
|
||||
* application code.
|
||||
*
|
||||
* <p>Requires Hibernate 3.6.x, as of Spring 4.0.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see #getSession
|
||||
* @see #releaseSession
|
||||
* @see HibernateTransactionManager
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class SessionFactoryUtils {
|
||||
|
||||
/**
|
||||
* Order value for TransactionSynchronization objects that clean up Hibernate Sessions.
|
||||
* Returns {@code 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;
|
||||
|
||||
static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
|
||||
|
||||
private static final ThreadLocal<Map<SessionFactory, Set<Session>>> deferredCloseHolder =
|
||||
new NamedThreadLocal<Map<SessionFactory, Set<Session>>>("Hibernate Sessions registered for deferred close");
|
||||
|
||||
|
||||
/**
|
||||
* Determine the DataSource of the given SessionFactory.
|
||||
* @param sessionFactory the SessionFactory to check
|
||||
* @return the DataSource, or {@code null} if none found
|
||||
* @see org.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);
|
||||
}
|
||||
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.
|
||||
* @param sessionFactory Hibernate SessionFactory
|
||||
* @param session Hibernate Session (can also be {@code null})
|
||||
* @return the JTA TransactionManager, if any
|
||||
* @see javax.transaction.TransactionManager
|
||||
* @see SessionFactoryImplementor#getTransactionManager
|
||||
* @see Session#getSessionFactory
|
||||
* @see org.hibernate.impl.SessionFactoryImpl
|
||||
*/
|
||||
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 {@link HibernateTransactionManager}. Will create a new
|
||||
* Session otherwise, if "allowCreate" is {@code true}.
|
||||
* <p>This is the {@code getSession} method used by typical data access code,
|
||||
* in combination with {@code releaseSession} called when done with
|
||||
* the Session. Note that HibernateTemplate allows to write data access code
|
||||
* without caring about such resource handling.
|
||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
||||
* @param allowCreate whether a non-transactional Session should be created
|
||||
* when no transactional Session can be found for the current thread
|
||||
* @return the Hibernate Session
|
||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
||||
* @throws IllegalStateException if no thread-bound Session found and
|
||||
* "allowCreate" is {@code false}
|
||||
* @see #getSession(SessionFactory, Interceptor, SQLExceptionTranslator)
|
||||
* @see #releaseSession
|
||||
* @see HibernateTemplate
|
||||
*/
|
||||
public static Session getSession(SessionFactory sessionFactory, boolean allowCreate)
|
||||
throws DataAccessResourceFailureException, IllegalStateException {
|
||||
|
||||
try {
|
||||
return doGetSession(sessionFactory, null, null, allowCreate);
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {@link HibernateTransactionManager}. Will always create
|
||||
* a new Session otherwise.
|
||||
* <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, etc.
|
||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
||||
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
|
||||
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
|
||||
* Session on transaction synchronization (may be {@code null}; only used
|
||||
* when actually registering a transaction synchronization)
|
||||
* @return the Hibernate Session
|
||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
||||
* @see LocalSessionFactoryBean#setEntityInterceptor
|
||||
* @see HibernateTemplate#setEntityInterceptor
|
||||
*/
|
||||
public static Session getSession(
|
||||
SessionFactory sessionFactory, Interceptor entityInterceptor,
|
||||
SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException {
|
||||
|
||||
try {
|
||||
return doGetSession(sessionFactory, entityInterceptor, jdbcExceptionTranslator, true);
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {@link HibernateTransactionManager}. Will create a new
|
||||
* Session otherwise, if "allowCreate" is {@code true}.
|
||||
* <p>Throws the original HibernateException, in contrast to {@link #getSession}.
|
||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
||||
* @param allowCreate whether a non-transactional Session should be created
|
||||
* when no transactional Session can be found for the current thread
|
||||
* @return the Hibernate Session
|
||||
* @throws HibernateException if the Session couldn't be created
|
||||
* @throws IllegalStateException if no thread-bound Session found and allowCreate false
|
||||
*/
|
||||
public static Session doGetSession(SessionFactory sessionFactory, boolean allowCreate)
|
||||
throws HibernateException, IllegalStateException {
|
||||
|
||||
return doGetSession(sessionFactory, null, null, 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 {@link HibernateTransactionManager}. Will create a new
|
||||
* Session otherwise, if "allowCreate" is {@code true}.
|
||||
* <p>Same as {@link #getSession}, but throwing the original HibernateException.
|
||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
||||
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
|
||||
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
|
||||
* Session on transaction synchronization (may be {@code null})
|
||||
* @param allowCreate whether a non-transactional Session should be created
|
||||
* when no transactional Session can be found for the current thread
|
||||
* @return the Hibernate Session
|
||||
* @throws HibernateException if the Session couldn't be created
|
||||
* @throws IllegalStateException if no thread-bound Session found and
|
||||
* "allowCreate" is {@code false}
|
||||
*/
|
||||
private static Session doGetSession(
|
||||
SessionFactory sessionFactory, Interceptor entityInterceptor,
|
||||
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)
|
||||
throws HibernateException, IllegalStateException {
|
||||
|
||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
||||
|
||||
Object resource = TransactionSynchronizationManager.getResource(sessionFactory);
|
||||
if (resource instanceof Session) {
|
||||
return (Session) resource;
|
||||
}
|
||||
SessionHolder sessionHolder = (SessionHolder) resource;
|
||||
if (sessionHolder != null && !sessionHolder.isEmpty()) {
|
||||
// pre-bound Hibernate Session
|
||||
Session session = null;
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive() &&
|
||||
sessionHolder.doesNotHoldNonDefaultSession()) {
|
||||
// Spring transaction management is active ->
|
||||
// register pre-bound Session with it for transactional flushing.
|
||||
session = sessionHolder.getValidatedSession();
|
||||
if (session != null && !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.MANUAL, which needs to allow flushing within the transaction.
|
||||
FlushMode flushMode = session.getFlushMode();
|
||||
if (flushMode.lessThan(FlushMode.COMMIT) &&
|
||||
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
||||
session.setFlushMode(FlushMode.AUTO);
|
||||
sessionHolder.setPreviousFlushMode(flushMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No Spring transaction management active -> try JTA transaction synchronization.
|
||||
session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);
|
||||
}
|
||||
if (session != null) {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("Opening Hibernate Session");
|
||||
Session session = (entityInterceptor != null ?
|
||||
sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());
|
||||
|
||||
// Use same Session for further Hibernate actions within the transaction.
|
||||
// Thread object will get removed by synchronization at transaction completion.
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
// We're within a Spring-managed transaction, possibly from JtaTransactionManager.
|
||||
logger.debug("Registering Spring transaction synchronization for new Hibernate Session");
|
||||
SessionHolder holderToUse = sessionHolder;
|
||||
if (holderToUse == null) {
|
||||
holderToUse = new SessionHolder(session);
|
||||
}
|
||||
else {
|
||||
holderToUse.addSession(session);
|
||||
}
|
||||
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
}
|
||||
TransactionSynchronizationManager.registerSynchronization(
|
||||
new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));
|
||||
holderToUse.setSynchronizedWithTransaction(true);
|
||||
if (holderToUse != sessionHolder) {
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No Spring transaction management active -> try JTA transaction synchronization.
|
||||
registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);
|
||||
}
|
||||
|
||||
// Check whether we are allowed to return the Session.
|
||||
if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {
|
||||
closeSession(session);
|
||||
throw new IllegalStateException("No Hibernate Session bound to thread, " +
|
||||
"and configuration does not allow creation of non-transactional one here");
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a Session from the given SessionHolder, potentially from a
|
||||
* JTA transaction synchronization.
|
||||
* @param sessionHolder the SessionHolder to check
|
||||
* @param sessionFactory the SessionFactory to get the JTA TransactionManager from
|
||||
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
|
||||
* Session on transaction synchronization (may be {@code null})
|
||||
* @return the associated Session, if any
|
||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
||||
*/
|
||||
private static Session getJtaSynchronizedSession(
|
||||
SessionHolder sessionHolder, SessionFactory sessionFactory,
|
||||
SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException {
|
||||
|
||||
// JTA synchronization is only possible with a javax.transaction.TransactionManager.
|
||||
// We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
|
||||
// in Hibernate configuration, it will contain a TransactionManager reference.
|
||||
TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
|
||||
if (jtaTm != null) {
|
||||
// Check whether JTA transaction management is active ->
|
||||
// fetch pre-bound Session for the current JTA transaction, if any.
|
||||
// (just necessary for JTA transaction suspension, with an individual
|
||||
// Hibernate Session per currently active/suspended transaction)
|
||||
try {
|
||||
// Look for transaction-specific Session.
|
||||
Transaction jtaTx = jtaTm.getTransaction();
|
||||
if (jtaTx != null) {
|
||||
int jtaStatus = jtaTx.getStatus();
|
||||
if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
|
||||
Session session = sessionHolder.getValidatedSession(jtaTx);
|
||||
if (session == null && !sessionHolder.isSynchronizedWithTransaction()) {
|
||||
// No transaction-specific Session found: If not already marked as
|
||||
// synchronized with transaction, register the default thread-bound
|
||||
// Session as JTA-transactional. If there is no default Session,
|
||||
// we're a new inner JTA transaction with an outer one being suspended:
|
||||
// In that case, we'll return null to trigger opening of a new Session.
|
||||
session = sessionHolder.getValidatedSession();
|
||||
if (session != null) {
|
||||
logger.debug("Registering JTA transaction synchronization for existing Hibernate Session");
|
||||
sessionHolder.addSession(jtaTx, session);
|
||||
jtaTx.registerSynchronization(
|
||||
new SpringJtaSynchronizationAdapter(
|
||||
new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false),
|
||||
jtaTm));
|
||||
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 = session.getFlushMode();
|
||||
if (flushMode.lessThan(FlushMode.COMMIT)) {
|
||||
session.setFlushMode(FlushMode.AUTO);
|
||||
sessionHolder.setPreviousFlushMode(flushMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return session;
|
||||
}
|
||||
}
|
||||
// No transaction active -> simply return default thread-bound Session, if any
|
||||
// (possibly from OpenSessionInViewFilter/Interceptor).
|
||||
return sessionHolder.getValidatedSession();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new DataAccessResourceFailureException("Could not check JTA transaction", ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No JTA TransactionManager -> simply return default thread-bound Session, if any
|
||||
// (possibly from OpenSessionInViewFilter/Interceptor).
|
||||
return sessionHolder.getValidatedSession();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a JTA synchronization for the given Session, if any.
|
||||
* @param sessionHolder the existing thread-bound SessionHolder, if any
|
||||
* @param session the Session to register
|
||||
* @param sessionFactory the SessionFactory that the Session was created with
|
||||
* @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
|
||||
* Session on transaction synchronization (may be {@code null})
|
||||
*/
|
||||
private static void registerJtaSynchronization(Session session, SessionFactory sessionFactory,
|
||||
SQLExceptionTranslator jdbcExceptionTranslator, SessionHolder sessionHolder) {
|
||||
|
||||
// JTA synchronization is only possible with a javax.transaction.TransactionManager.
|
||||
// We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
|
||||
// in Hibernate configuration, it will contain a TransactionManager reference.
|
||||
TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, session);
|
||||
if (jtaTm != null) {
|
||||
try {
|
||||
Transaction jtaTx = jtaTm.getTransaction();
|
||||
if (jtaTx != null) {
|
||||
int jtaStatus = jtaTx.getStatus();
|
||||
if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
|
||||
logger.debug("Registering JTA transaction synchronization for new Hibernate Session");
|
||||
SessionHolder holderToUse = sessionHolder;
|
||||
// Register JTA Transaction with existing SessionHolder.
|
||||
// Create a new SessionHolder if none existed before.
|
||||
if (holderToUse == null) {
|
||||
holderToUse = new SessionHolder(jtaTx, session);
|
||||
}
|
||||
else {
|
||||
holderToUse.addSession(jtaTx, session);
|
||||
}
|
||||
jtaTx.registerSynchronization(
|
||||
new SpringJtaSynchronizationAdapter(
|
||||
new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true),
|
||||
jtaTm));
|
||||
holderToUse.setSynchronizedWithTransaction(true);
|
||||
if (holderToUse != sessionHolder) {
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new DataAccessResourceFailureException(
|
||||
"Could not register synchronization with JTA TransactionManager", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a new Hibernate Session from the given SessionFactory.
|
||||
* Will return a new Session even if there already is a pre-bound
|
||||
* Session for the given SessionFactory.
|
||||
* <p>Within a transaction, this method will create a new Session
|
||||
* that shares the transaction's JDBC Connection. More specifically,
|
||||
* it will use the same JDBC Connection as the pre-bound Hibernate Session.
|
||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
||||
* @return the new Session
|
||||
*/
|
||||
public static Session getNewSession(SessionFactory sessionFactory) {
|
||||
return getNewSession(sessionFactory, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new Hibernate Session from the given SessionFactory.
|
||||
* Will return a new Session even if there already is a pre-bound
|
||||
* Session for the given SessionFactory.
|
||||
* <p>Within a transaction, this method will create a new Session
|
||||
* that shares the transaction's JDBC Connection. More specifically,
|
||||
* it will use the same JDBC Connection as the pre-bound Hibernate Session.
|
||||
* @param sessionFactory Hibernate SessionFactory to create the session with
|
||||
* @param entityInterceptor Hibernate entity interceptor, or {@code null} if none
|
||||
* @return the new Session
|
||||
*/
|
||||
public static Session getNewSession(SessionFactory sessionFactory, Interceptor entityInterceptor) {
|
||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
||||
|
||||
try {
|
||||
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
||||
if (sessionHolder != null && !sessionHolder.isEmpty()) {
|
||||
if (entityInterceptor != null) {
|
||||
return sessionFactory.openSession(sessionHolder.getAnySession().connection(), entityInterceptor);
|
||||
}
|
||||
else {
|
||||
return sessionFactory.openSession(sessionHolder.getAnySession().connection());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (entityInterceptor != null) {
|
||||
return sessionFactory.openSession(entityInterceptor);
|
||||
}
|
||||
else {
|
||||
return sessionFactory.openSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stringify the given Session for debug logging.
|
||||
* Returns output equivalent to {@code Object.toString()}:
|
||||
* the fully qualified class name + "@" + the identity hash code.
|
||||
* <p>The sole reason why this is necessary is because Hibernate3's
|
||||
* {@code Session.toString()} implementation is broken (and won't be fixed):
|
||||
* it logs the toString representation of all persistent objects in the Session,
|
||||
* which might lead to ConcurrentModificationExceptions if the persistent objects
|
||||
* in turn refer to the Session (for example, for lazy loading).
|
||||
* @param session the Hibernate Session to stringify
|
||||
* @return the String representation of the given Session
|
||||
*/
|
||||
public static String toString(Session session) {
|
||||
return session.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(session));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether there is a transactional Hibernate Session for the current thread,
|
||||
* that is, a Session bound to the current thread by Spring's transaction facilities.
|
||||
* @param sessionFactory Hibernate SessionFactory to check (may be {@code null})
|
||||
* @return whether there is a transactional Session for current thread
|
||||
*/
|
||||
public static boolean hasTransactionalSession(SessionFactory sessionFactory) {
|
||||
if (sessionFactory == null) {
|
||||
return false;
|
||||
}
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
||||
return (sessionHolder != null && !sessionHolder.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given Hibernate Session is transactional, that is,
|
||||
* bound to the current thread by Spring's transaction facilities.
|
||||
* @param session the Hibernate Session to check
|
||||
* @param sessionFactory Hibernate SessionFactory that the Session was created with
|
||||
* (may be {@code null})
|
||||
* @return whether the Session is transactional
|
||||
*/
|
||||
public static boolean isSessionTransactional(Session session, SessionFactory sessionFactory) {
|
||||
if (sessionFactory == null) {
|
||||
return false;
|
||||
}
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
||||
return (sessionHolder != null && sessionHolder.containsSession(session));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the current transaction timeout, if any, to the given
|
||||
* Hibernate Query object.
|
||||
* @param query the Hibernate Query object
|
||||
* @param sessionFactory Hibernate SessionFactory that the Query was created for
|
||||
* (may be {@code null})
|
||||
* @see org.hibernate.Query#setTimeout
|
||||
*/
|
||||
public static void applyTransactionTimeout(Query query, SessionFactory sessionFactory) {
|
||||
Assert.notNull(query, "No Query object specified");
|
||||
if (sessionFactory != null) {
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
||||
if (sessionHolder != null && sessionHolder.hasTimeout()) {
|
||||
query.setTimeout(sessionHolder.getTimeToLiveInSeconds());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the current transaction timeout, if any, to the given
|
||||
* Hibernate Criteria object.
|
||||
* @param criteria the Hibernate Criteria object
|
||||
* @param sessionFactory Hibernate SessionFactory that the Criteria was created for
|
||||
* @see org.hibernate.Criteria#setTimeout
|
||||
*/
|
||||
public static void applyTransactionTimeout(Criteria criteria, SessionFactory sessionFactory) {
|
||||
Assert.notNull(criteria, "No Criteria object specified");
|
||||
if (sessionFactory != null) {
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
|
||||
if (sessionHolder != null && sessionHolder.hasTimeout()) {
|
||||
criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given HibernateException to an appropriate exception
|
||||
* from the {@code org.springframework.dao} hierarchy.
|
||||
* @param ex HibernateException that occurred
|
||||
* @return the corresponding DataAccessException instance
|
||||
* @see HibernateAccessor#convertHibernateAccessException
|
||||
* @see HibernateTransactionManager#convertHibernateAccessException
|
||||
*/
|
||||
public static DataAccessException convertHibernateAccessException(HibernateException ex) {
|
||||
if (ex instanceof JDBCConnectionException) {
|
||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof SQLGrammarException) {
|
||||
SQLGrammarException jdbcEx = (SQLGrammarException) ex;
|
||||
return new InvalidDataAccessResourceUsageException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof QueryTimeoutException) {
|
||||
QueryTimeoutException jdbcEx = (QueryTimeoutException) ex;
|
||||
return new org.springframework.dao.QueryTimeoutException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof LockAcquisitionException) {
|
||||
LockAcquisitionException jdbcEx = (LockAcquisitionException) ex;
|
||||
return new CannotAcquireLockException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof PessimisticLockException) {
|
||||
PessimisticLockException jdbcEx = (PessimisticLockException) ex;
|
||||
return new PessimisticLockingFailureException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof ConstraintViolationException) {
|
||||
ConstraintViolationException jdbcEx = (ConstraintViolationException) ex;
|
||||
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() +
|
||||
"]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
|
||||
}
|
||||
if (ex instanceof DataException) {
|
||||
DataException jdbcEx = (DataException) ex;
|
||||
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof JDBCException) {
|
||||
return new HibernateJdbcException((JDBCException) ex);
|
||||
}
|
||||
// end of JDBCException (subclass) handling
|
||||
|
||||
if (ex instanceof QueryException) {
|
||||
return new HibernateQueryException((QueryException) ex);
|
||||
}
|
||||
if (ex instanceof NonUniqueResultException) {
|
||||
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
|
||||
}
|
||||
if (ex instanceof NonUniqueObjectException) {
|
||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof PropertyValueException) {
|
||||
return new DataIntegrityViolationException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof PersistentObjectException) {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof TransientObjectException) {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof ObjectDeletedException) {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof UnresolvableObjectException) {
|
||||
return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex);
|
||||
}
|
||||
if (ex instanceof WrongClassException) {
|
||||
return new HibernateObjectRetrievalFailureException((WrongClassException) ex);
|
||||
}
|
||||
if (ex instanceof StaleObjectStateException) {
|
||||
return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex);
|
||||
}
|
||||
if (ex instanceof StaleStateException) {
|
||||
return new HibernateOptimisticLockingFailureException((StaleStateException) ex);
|
||||
}
|
||||
if (ex instanceof OptimisticLockException) {
|
||||
return new HibernateOptimisticLockingFailureException((OptimisticLockException) ex);
|
||||
}
|
||||
|
||||
// fallback
|
||||
return new HibernateSystemException(ex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether deferred close is active for the current thread
|
||||
* and the given SessionFactory.
|
||||
* @param sessionFactory the Hibernate SessionFactory to check
|
||||
* @return whether deferred close is active
|
||||
*/
|
||||
public static boolean isDeferredCloseActive(SessionFactory sessionFactory) {
|
||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
||||
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
|
||||
return (holderMap != null && holderMap.containsKey(sessionFactory));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize deferred close for the current thread and the given SessionFactory.
|
||||
* Sessions will not be actually closed on close calls then, but rather at a
|
||||
* {@link #processDeferredClose} call at a finishing point (like request completion).
|
||||
* <p>Used by {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter}
|
||||
* and {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}
|
||||
* when not configured for a single session.
|
||||
* @param sessionFactory the Hibernate SessionFactory to initialize deferred close for
|
||||
* @see #processDeferredClose
|
||||
* @see #releaseSession
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter#setSingleSession
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor#setSingleSession
|
||||
*/
|
||||
public static void initDeferredClose(SessionFactory sessionFactory) {
|
||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
||||
logger.debug("Initializing deferred close of Hibernate Sessions");
|
||||
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
|
||||
if (holderMap == null) {
|
||||
holderMap = new HashMap<SessionFactory, Set<Session>>();
|
||||
deferredCloseHolder.set(holderMap);
|
||||
}
|
||||
holderMap.put(sessionFactory, new LinkedHashSet<Session>(4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all Hibernate Sessions that have been registered for deferred close
|
||||
* for the given SessionFactory.
|
||||
* @param sessionFactory the Hibernate SessionFactory to process deferred close for
|
||||
* @see #initDeferredClose
|
||||
* @see #releaseSession
|
||||
*/
|
||||
public static void processDeferredClose(SessionFactory sessionFactory) {
|
||||
Assert.notNull(sessionFactory, "No SessionFactory specified");
|
||||
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
|
||||
if (holderMap == null || !holderMap.containsKey(sessionFactory)) {
|
||||
throw new IllegalStateException("Deferred close not active for SessionFactory [" + sessionFactory + "]");
|
||||
}
|
||||
logger.debug("Processing deferred close of Hibernate Sessions");
|
||||
Set<Session> sessions = holderMap.remove(sessionFactory);
|
||||
for (Session session : sessions) {
|
||||
closeSession(session);
|
||||
}
|
||||
if (holderMap.isEmpty()) {
|
||||
deferredCloseHolder.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the given Session, created via the given factory,
|
||||
* if it is not managed externally (i.e. not bound to the thread).
|
||||
* @param session the Hibernate Session to close (may be {@code null})
|
||||
* @param sessionFactory Hibernate SessionFactory that the Session was created with
|
||||
* (may be {@code null})
|
||||
*/
|
||||
public static void releaseSession(Session session, SessionFactory sessionFactory) {
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
// Only close non-transactional Sessions.
|
||||
if (!isSessionTransactional(session, sessionFactory)) {
|
||||
closeSessionOrRegisterDeferredClose(session, sessionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the given Session or register it for deferred close.
|
||||
* @param session the Hibernate Session to close
|
||||
* @param sessionFactory Hibernate SessionFactory that the Session was created with
|
||||
* (may be {@code null})
|
||||
* @see #initDeferredClose
|
||||
* @see #processDeferredClose
|
||||
*/
|
||||
static void closeSessionOrRegisterDeferredClose(Session session, SessionFactory sessionFactory) {
|
||||
Map<SessionFactory, Set<Session>> holderMap = deferredCloseHolder.get();
|
||||
if (holderMap != null && sessionFactory != null && holderMap.containsKey(sessionFactory)) {
|
||||
logger.debug("Registering Hibernate Session for deferred close");
|
||||
// Switch Session to FlushMode.MANUAL for remaining lifetime.
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
Set<Session> sessions = holderMap.get(sessionFactory);
|
||||
sessions.add(session);
|
||||
}
|
||||
else {
|
||||
closeSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform actual closing of the Hibernate Session,
|
||||
* catching and logging any cleanup exceptions thrown.
|
||||
* @param session the Hibernate Session to close (may be {@code null})
|
||||
* @see org.hibernate.Session#close()
|
||||
*/
|
||||
public static void closeSession(Session session) {
|
||||
if (session != null) {
|
||||
logger.debug("Closing Hibernate Session");
|
||||
try {
|
||||
session.close();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
logger.debug("Could not close Hibernate Session", ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Unexpected exception on closing Hibernate Session", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
|
||||
import org.springframework.transaction.support.ResourceHolderSupport;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
|
||||
* HibernateTransactionManager binds instances of this class to the thread,
|
||||
* for a given SessionFactory.
|
||||
*
|
||||
* <p>Note: This is an SPI class, not intended to be used by applications.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see HibernateTransactionManager
|
||||
* @see SessionFactoryUtils
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class SessionHolder extends ResourceHolderSupport {
|
||||
|
||||
private static final Object DEFAULT_KEY = new Object();
|
||||
|
||||
/**
|
||||
* This Map needs to be concurrent because there might be multi-threaded
|
||||
* access in the case of JTA with remote transaction propagation.
|
||||
*/
|
||||
private final Map<Object, Session> sessionMap = new ConcurrentHashMap<Object, Session>(1);
|
||||
|
||||
private Transaction transaction;
|
||||
|
||||
private FlushMode previousFlushMode;
|
||||
|
||||
|
||||
public SessionHolder(Session session) {
|
||||
addSession(session);
|
||||
}
|
||||
|
||||
public SessionHolder(Object key, Session session) {
|
||||
addSession(key, session);
|
||||
}
|
||||
|
||||
|
||||
public Session getSession() {
|
||||
return getSession(DEFAULT_KEY);
|
||||
}
|
||||
|
||||
public Session getSession(Object key) {
|
||||
return this.sessionMap.get(key);
|
||||
}
|
||||
|
||||
public Session getValidatedSession() {
|
||||
return getValidatedSession(DEFAULT_KEY);
|
||||
}
|
||||
|
||||
public Session getValidatedSession(Object key) {
|
||||
Session session = this.sessionMap.get(key);
|
||||
// Check for dangling Session that's around but already closed.
|
||||
// Effectively an assertion: that should never happen in practice.
|
||||
// We'll seamlessly remove the Session here, to not let it cause
|
||||
// any side effects.
|
||||
if (session != null && !session.isOpen()) {
|
||||
this.sessionMap.remove(key);
|
||||
session = null;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
public Session getAnySession() {
|
||||
if (!this.sessionMap.isEmpty()) {
|
||||
return this.sessionMap.values().iterator().next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addSession(Session session) {
|
||||
addSession(DEFAULT_KEY, session);
|
||||
}
|
||||
|
||||
public void addSession(Object key, Session session) {
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
this.sessionMap.put(key, session);
|
||||
}
|
||||
|
||||
public Session removeSession(Object key) {
|
||||
return this.sessionMap.remove(key);
|
||||
}
|
||||
|
||||
public boolean containsSession(Session session) {
|
||||
return this.sessionMap.containsValue(session);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.sessionMap.isEmpty();
|
||||
}
|
||||
|
||||
public boolean doesNotHoldNonDefaultSession() {
|
||||
return this.sessionMap.isEmpty() ||
|
||||
(this.sessionMap.size() == 1 && this.sessionMap.containsKey(DEFAULT_KEY));
|
||||
}
|
||||
|
||||
|
||||
public void setTransaction(Transaction transaction) {
|
||||
this.transaction = transaction;
|
||||
}
|
||||
|
||||
public Transaction getTransaction() {
|
||||
return this.transaction;
|
||||
}
|
||||
|
||||
public void setPreviousFlushMode(FlushMode previousFlushMode) {
|
||||
this.previousFlushMode = previousFlushMode;
|
||||
}
|
||||
|
||||
public FlushMode getPreviousFlushMode() {
|
||||
return this.previousFlushMode;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
this.transaction = null;
|
||||
this.previousFlushMode = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.classic.Session;
|
||||
import org.hibernate.context.CurrentSessionContext;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
|
||||
/**
|
||||
* Implementation of Hibernate 3.1's CurrentSessionContext interface
|
||||
* that delegates to Spring's SessionFactoryUtils for providing a
|
||||
* Spring-managed current Session.
|
||||
*
|
||||
* <p>Used by Spring's {@link LocalSessionFactoryBean} when told to expose a
|
||||
* transaction-aware SessionFactory. This is the default as of Spring 2.5.
|
||||
*
|
||||
* <p>This CurrentSessionContext implementation can also be specified in custom
|
||||
* SessionFactory setup through the "hibernate.current_session_context_class"
|
||||
* property, with the fully qualified name of this class as value.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see SessionFactoryUtils#doGetSession
|
||||
* @see LocalSessionFactoryBean#setExposeTransactionAwareSessionFactory
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("serial")
|
||||
public class SpringSessionContext implements CurrentSessionContext {
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SpringSessionContext for the given Hibernate SessionFactory.
|
||||
* @param sessionFactory the SessionFactory to provide current Sessions for
|
||||
*/
|
||||
public SpringSessionContext(SessionFactoryImplementor sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the Spring-managed Session for the current thread, if any.
|
||||
*/
|
||||
@Override
|
||||
public Session currentSession() throws HibernateException {
|
||||
try {
|
||||
return (org.hibernate.classic.Session) SessionFactoryUtils.doGetSession(this.sessionFactory, false);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new HibernateException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,268 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* Callback for resource cleanup at the end of a Spring-managed JTA transaction,
|
||||
* that is, when participating in a JtaTransactionManager transaction.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see SessionFactoryUtils
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
class SpringSessionSynchronization implements TransactionSynchronization, Ordered {
|
||||
|
||||
private final SessionHolder sessionHolder;
|
||||
|
||||
private final SessionFactory sessionFactory;
|
||||
|
||||
private final SQLExceptionTranslator jdbcExceptionTranslator;
|
||||
|
||||
private final boolean newSession;
|
||||
|
||||
/**
|
||||
* Whether Hibernate has a looked-up JTA TransactionManager that it will
|
||||
* automatically register CacheSynchronizations with on Session connect.
|
||||
*/
|
||||
private boolean hibernateTransactionCompletion = false;
|
||||
|
||||
private Transaction jtaTransaction;
|
||||
|
||||
private boolean holderActive = true;
|
||||
|
||||
|
||||
public SpringSessionSynchronization(
|
||||
SessionHolder sessionHolder, SessionFactory sessionFactory,
|
||||
SQLExceptionTranslator jdbcExceptionTranslator, boolean newSession) {
|
||||
|
||||
this.sessionHolder = sessionHolder;
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
|
||||
this.newSession = newSession;
|
||||
|
||||
// Check whether the SessionFactory has a JTA TransactionManager.
|
||||
TransactionManager jtaTm =
|
||||
SessionFactoryUtils.getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
|
||||
if (jtaTm != null) {
|
||||
this.hibernateTransactionCompletion = true;
|
||||
// Fetch current JTA Transaction object
|
||||
// (just necessary for JTA transaction suspension, with an individual
|
||||
// Hibernate Session per currently active/suspended transaction).
|
||||
try {
|
||||
this.jtaTransaction = jtaTm.getTransaction();
|
||||
}
|
||||
catch (SystemException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not access JTA transaction", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there is a Hibernate Session for the current JTA
|
||||
* transaction. Else, fall back to the default thread-bound Session.
|
||||
*/
|
||||
private Session getCurrentSession() {
|
||||
Session session = null;
|
||||
if (this.jtaTransaction != null) {
|
||||
session = this.sessionHolder.getSession(this.jtaTransaction);
|
||||
}
|
||||
if (session == null) {
|
||||
session = this.sessionHolder.getSession();
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suspend() {
|
||||
if (this.holderActive) {
|
||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
||||
// Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss.
|
||||
getCurrentSession().disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
if (this.holderActive) {
|
||||
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
try {
|
||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
|
||||
getCurrentSession().flush();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw translateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCommit(boolean readOnly) throws DataAccessException {
|
||||
if (!readOnly) {
|
||||
Session session = getCurrentSession();
|
||||
// Read-write transaction -> flush the Hibernate Session.
|
||||
// Further check: only flush when not FlushMode.NEVER/MANUAL.
|
||||
if (!session.getFlushMode().lessThan(FlushMode.COMMIT)) {
|
||||
try {
|
||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization");
|
||||
session.flush();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw translateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DataAccessException translateException(HibernateException ex) {
|
||||
if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
|
||||
JDBCException jdbcEx = (JDBCException) ex;
|
||||
return this.jdbcExceptionTranslator.translate(
|
||||
"Hibernate flushing: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
|
||||
}
|
||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCompletion() {
|
||||
if (this.jtaTransaction != null) {
|
||||
// Typically in case of a suspended JTA transaction:
|
||||
// Remove the Session for the current JTA transaction, but keep the holder.
|
||||
Session session = this.sessionHolder.removeSession(this.jtaTransaction);
|
||||
if (session != null) {
|
||||
if (this.sessionHolder.isEmpty()) {
|
||||
// No Sessions for JTA transactions bound anymore -> could remove it.
|
||||
TransactionSynchronizationManager.unbindResourceIfPossible(this.sessionFactory);
|
||||
this.holderActive = false;
|
||||
}
|
||||
// Do not close a pre-bound Session. In that case, we'll find the
|
||||
// transaction-specific Session the same as the default Session.
|
||||
if (session != this.sessionHolder.getSession()) {
|
||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
|
||||
}
|
||||
else {
|
||||
if (this.sessionHolder.getPreviousFlushMode() != null) {
|
||||
// In case of pre-bound Session, restore previous flush mode.
|
||||
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
|
||||
}
|
||||
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
|
||||
session.disconnect();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// We'll only get here if there was no specific JTA transaction to handle.
|
||||
if (this.newSession) {
|
||||
// Default behavior: unbind and close the thread-bound Hibernate Session.
|
||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
||||
this.holderActive = false;
|
||||
if (this.hibernateTransactionCompletion) {
|
||||
// Close the Hibernate Session here in case of a Hibernate TransactionManagerLookup:
|
||||
// Hibernate will automatically defer the actual closing until JTA transaction completion.
|
||||
// Else, the Session will be closed in the afterCompletion method, to provide the
|
||||
// correct transaction status for releasing the Session's cache locks.
|
||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(this.sessionHolder.getSession(), this.sessionFactory);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Session session = this.sessionHolder.getSession();
|
||||
if (this.sessionHolder.getPreviousFlushMode() != null) {
|
||||
// In case of pre-bound Session, restore previous flush mode.
|
||||
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
|
||||
}
|
||||
if (this.hibernateTransactionCompletion) {
|
||||
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
|
||||
// We know that this is appropriate if a TransactionManagerLookup has been specified.
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
try {
|
||||
if (!this.hibernateTransactionCompletion || !this.newSession) {
|
||||
// No Hibernate TransactionManagerLookup: apply afterTransactionCompletion callback.
|
||||
// Always perform explicit afterTransactionCompletion callback for pre-bound Session,
|
||||
// even with Hibernate TransactionManagerLookup (which only applies to new Sessions).
|
||||
Session session = this.sessionHolder.getSession();
|
||||
// Provide correct transaction status for releasing the Session's cache locks,
|
||||
// if possible. Else, closing will release all cache locks assuming a rollback.
|
||||
try {
|
||||
if (session instanceof SessionImplementor) {
|
||||
((SessionImplementor) session).afterTransactionCompletion(status == STATUS_COMMITTED, null);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Close the Hibernate Session here if necessary
|
||||
// (closed in beforeCompletion in case of TransactionManagerLookup).
|
||||
if (this.newSession) {
|
||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
|
||||
}
|
||||
else if (!this.hibernateTransactionCompletion) {
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.newSession && status != STATUS_COMMITTED) {
|
||||
// Clear all pending inserts/updates/deletes in the Session.
|
||||
// Necessary for pre-bound Sessions, to avoid inconsistent state.
|
||||
this.sessionHolder.getSession().clear();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (this.sessionHolder.doesNotHoldNonDefaultSession()) {
|
||||
this.sessionHolder.setSynchronizedWithTransaction(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.jdbc.JDBCContext;
|
||||
import org.hibernate.transaction.JDBCTransaction;
|
||||
import org.hibernate.transaction.TransactionFactory;
|
||||
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* Spring-aware implementation of the Hibernate TransactionFactory interface, aware of
|
||||
* Spring-synchronized transactions (in particular Spring-managed JTA transactions)
|
||||
* and asking for default release mode ON_CLOSE. Otherwise identical to Hibernate's
|
||||
* default {@link org.hibernate.transaction.JDBCTransactionFactory} implementation.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.4
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* @see org.hibernate.transaction.JDBCTransactionFactory
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class SpringTransactionFactory implements TransactionFactory {
|
||||
|
||||
/**
|
||||
* Sets connection release mode "on_close" as default.
|
||||
* <p>This was the case for Hibernate 3.0; Hibernate 3.1 changed
|
||||
* it to "auto" (i.e. "after_statement" or "after_transaction").
|
||||
* However, for Spring's resource management (in particular for
|
||||
* HibernateTransactionManager), "on_close" is the better default.
|
||||
*/
|
||||
@Override
|
||||
public ConnectionReleaseMode getDefaultReleaseMode() {
|
||||
return ConnectionReleaseMode.ON_CLOSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext) {
|
||||
return new JDBCTransaction(jdbcContext, transactionContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Properties props) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionManagerRequired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areCallbacksLocalToHibernateTransactions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionInProgress(
|
||||
JDBCContext jdbcContext, Context transactionContext, Transaction transaction) {
|
||||
|
||||
return (transaction != null && transaction.isActive()) ||
|
||||
TransactionSynchronizationManager.isActualTransactionActive();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
|
||||
|
||||
/**
|
||||
* Subclass of LocalDataSourceConnectionProvider that returns a
|
||||
* transaction-aware proxy for the exposed DataSource. Used if
|
||||
* LocalSessionFactoryBean's "useTransactionAwareDataSource" flag is on.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see LocalSessionFactoryBean#setUseTransactionAwareDataSource
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class TransactionAwareDataSourceConnectionProvider extends LocalDataSourceConnectionProvider {
|
||||
|
||||
/**
|
||||
* Return a TransactionAwareDataSourceProxy for the given DataSource,
|
||||
* provided that it isn't a TransactionAwareDataSourceProxy already.
|
||||
*/
|
||||
@Override
|
||||
protected DataSource getDataSourceToUse(DataSource originalDataSource) {
|
||||
if (originalDataSource instanceof TransactionAwareDataSourceProxy) {
|
||||
return originalDataSource;
|
||||
}
|
||||
return new TransactionAwareDataSourceProxy(originalDataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns {@code true}: We can guarantee
|
||||
* to receive the same Connection within a transaction, as we are
|
||||
* exposing a TransactionAwareDataSourceProxy.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsAggressiveRelease() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Bean that encapsulates a Hibernate type definition.
|
||||
*
|
||||
* <p>Typically defined as inner bean within a LocalSessionFactoryBean
|
||||
* definition, as list element for the "typeDefinitions" bean property.
|
||||
* For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
|
||||
* ...
|
||||
* <property name="typeDefinitions">
|
||||
* <list>
|
||||
* <bean class="org.springframework.orm.hibernate3.TypeDefinitionBean">
|
||||
* <property name="typeName" value="myType"/>
|
||||
* <property name="typeClass" value="mypackage.MyTypeClass"/>
|
||||
* </bean>
|
||||
* </list>
|
||||
* </property>
|
||||
* ...
|
||||
* </bean></pre>
|
||||
*
|
||||
* Alternatively, specify a bean id (or name) attribute for the inner bean,
|
||||
* instead of the "typeName" property.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see LocalSessionFactoryBean#setTypeDefinitions(TypeDefinitionBean[])
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class TypeDefinitionBean implements BeanNameAware, InitializingBean {
|
||||
|
||||
private String typeName;
|
||||
|
||||
private String typeClass;
|
||||
|
||||
private Properties parameters = new Properties();
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the type.
|
||||
* @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
|
||||
*/
|
||||
public void setTypeName(String typeName) {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the type.
|
||||
*/
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type implementation class.
|
||||
* @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
|
||||
*/
|
||||
public void setTypeClass(String typeClass) {
|
||||
this.typeClass = typeClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type implementation class.
|
||||
*/
|
||||
public String getTypeClass() {
|
||||
return typeClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify default parameters for the type.
|
||||
* This only applies to parameterized types.
|
||||
* @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
|
||||
* @see org.hibernate.usertype.ParameterizedType
|
||||
*/
|
||||
public void setParameters(Properties parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default parameters for the type.
|
||||
*/
|
||||
public Properties getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If no explicit type name has been specified, the bean name of
|
||||
* the TypeDefinitionBean will be used.
|
||||
* @see #setTypeName
|
||||
*/
|
||||
@Override
|
||||
public void setBeanName(String name) {
|
||||
if (this.typeName == null) {
|
||||
this.typeName = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (this.typeName == null) {
|
||||
throw new IllegalArgumentException("typeName is required");
|
||||
}
|
||||
if (this.typeClass == null) {
|
||||
throw new IllegalArgumentException("typeClass is required");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.hibernate3.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Subclass of Spring's standard LocalSessionFactoryBean for Hibernate,
|
||||
* supporting annotation metadata for mappings.
|
||||
*
|
||||
* <p>Example for an AnnotationSessionFactoryBean bean definition:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
|
||||
* <property name="dataSource" ref="dataSource"/>
|
||||
* <property name="annotatedClasses">
|
||||
* <list>
|
||||
* <value>test.package.Foo</value>
|
||||
* <value>test.package.Bar</value>
|
||||
* </list>
|
||||
* </property>
|
||||
* </bean></pre>
|
||||
*
|
||||
* Or when using classpath scanning for autodetection of entity classes:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
|
||||
* <property name="dataSource" ref="dataSource"/>
|
||||
* <property name="packagesToScan" value="test.package"/>
|
||||
* </bean></pre>
|
||||
*
|
||||
* <p>Requires Hibernate 3.6.x, as of Spring 4.0.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2.2
|
||||
* @see #setDataSource
|
||||
* @see #setHibernateProperties
|
||||
* @see #setAnnotatedClasses
|
||||
* @see #setAnnotatedPackages
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class AnnotationSessionFactoryBean extends org.springframework.orm.hibernate3.LocalSessionFactoryBean
|
||||
implements ResourceLoaderAware {
|
||||
|
||||
private static final String RESOURCE_PATTERN = "/**/*.class";
|
||||
|
||||
private static final String PACKAGE_INFO_SUFFIX = ".package-info";
|
||||
|
||||
|
||||
private Class<?>[] annotatedClasses;
|
||||
|
||||
private String[] annotatedPackages;
|
||||
|
||||
private String[] packagesToScan;
|
||||
|
||||
private TypeFilter[] entityTypeFilters = new TypeFilter[] {
|
||||
new AnnotationTypeFilter(Entity.class, false),
|
||||
new AnnotationTypeFilter(Embeddable.class, false),
|
||||
new AnnotationTypeFilter(MappedSuperclass.class, false),
|
||||
new AnnotationTypeFilter(org.hibernate.annotations.Entity.class, false)};
|
||||
|
||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
|
||||
|
||||
/**
|
||||
* Specify annotated classes, for which mappings will be read from
|
||||
* class-level annotation metadata.
|
||||
* @see org.hibernate.cfg.Configuration#addAnnotatedClass(Class)
|
||||
*/
|
||||
public void setAnnotatedClasses(Class<?>... annotatedClasses) {
|
||||
this.annotatedClasses = annotatedClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the names of annotated packages, for which package-level
|
||||
* annotation metadata will be read.
|
||||
* @see org.hibernate.cfg.Configuration#addPackage(String)
|
||||
*/
|
||||
public void setAnnotatedPackages(String... annotatedPackages) {
|
||||
this.annotatedPackages = annotatedPackages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify packages to search using Spring-based scanning for entity classes in
|
||||
* the classpath. This is an alternative to listing annotated classes explicitly.
|
||||
* <p>Default is none. Specify packages to search for autodetection of your entity
|
||||
* classes in the classpath. This is analogous to Spring's component-scan feature
|
||||
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
|
||||
*/
|
||||
public void setPackagesToScan(String... packagesToScan) {
|
||||
this.packagesToScan = packagesToScan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify custom type filters for Spring-based scanning for entity classes.
|
||||
* <p>Default is to search all specified packages for classes annotated with
|
||||
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
|
||||
* or {@code @javax.persistence.MappedSuperclass}, as well as for
|
||||
* Hibernate's special {@code @org.hibernate.annotations.Entity}.
|
||||
* @see #setPackagesToScan
|
||||
*/
|
||||
public void setEntityTypeFilters(TypeFilter... entityTypeFilters) {
|
||||
this.entityTypeFilters = entityTypeFilters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads metadata from annotated classes and packages into the
|
||||
* AnnotationConfiguration instance.
|
||||
*/
|
||||
@Override
|
||||
protected void postProcessMappings(Configuration config) throws HibernateException {
|
||||
if (this.annotatedClasses != null) {
|
||||
for (Class<?> annotatedClass : this.annotatedClasses) {
|
||||
config.addAnnotatedClass(annotatedClass);
|
||||
}
|
||||
}
|
||||
if (this.annotatedPackages != null) {
|
||||
for (String annotatedPackage : this.annotatedPackages) {
|
||||
config.addPackage(annotatedPackage);
|
||||
}
|
||||
}
|
||||
scanPackages(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform Spring-based scanning for entity classes.
|
||||
* @see #setPackagesToScan
|
||||
*/
|
||||
protected void scanPackages(Configuration config) {
|
||||
if (this.packagesToScan != null) {
|
||||
Set<String> classNames = new TreeSet<String>();
|
||||
Set<String> packageNames = new TreeSet<String>();
|
||||
try {
|
||||
for (String pkg : this.packagesToScan) {
|
||||
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
|
||||
ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
|
||||
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
|
||||
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
|
||||
for (Resource resource : resources) {
|
||||
if (resource.isReadable()) {
|
||||
MetadataReader reader = readerFactory.getMetadataReader(resource);
|
||||
String className = reader.getClassMetadata().getClassName();
|
||||
if (matchesEntityTypeFilter(reader, readerFactory)) {
|
||||
classNames.add(className);
|
||||
}
|
||||
else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
|
||||
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new MappingException("Failed to scan classpath for unlisted classes", ex);
|
||||
}
|
||||
try {
|
||||
for (String className : classNames) {
|
||||
config.addAnnotatedClass(this.resourcePatternResolver.getClassLoader().loadClass(className));
|
||||
}
|
||||
for (String packageName : packageNames) {
|
||||
config.addPackage(packageName);
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new MappingException("Failed to load annotated classes from classpath", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether any of the configured entity type filters matches
|
||||
* the current class descriptor contained in the metadata reader.
|
||||
*/
|
||||
private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
|
||||
if (this.entityTypeFilters != null) {
|
||||
for (TypeFilter filter : this.entityTypeFilters) {
|
||||
if (filter.match(reader, readerFactory)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* Support package for the Hibernate 3 Annotation add-on,
|
||||
* which supports JPA-compliant Java 5+ annotations for mappings.
|
||||
*/
|
||||
package org.springframework.orm.hibernate3.annotation;
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Package providing integration of
|
||||
* <a href="http://www.hibernate.org">Hibernate 3.x</a>
|
||||
* with Spring concepts.
|
||||
*
|
||||
* <p>Contains SessionFactory helper classes, a template plus callback
|
||||
* for Hibernate access, and an implementation of Spring's transaction SPI
|
||||
* for local Hibernate transactions.
|
||||
*
|
||||
* <p><b>This package supports Hibernate 3.x only.</b>
|
||||
* See the {@code org.springframework.orm.hibernate4} package for Hibernate 4.x support.
|
||||
*/
|
||||
package org.springframework.orm.hibernate3;
|
||||
@@ -1,223 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.usertype.UserType;
|
||||
import org.hibernate.util.EqualsHelper;
|
||||
|
||||
import org.springframework.jdbc.support.lob.LobCreator;
|
||||
import org.springframework.jdbc.support.lob.LobCreatorUtils;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
|
||||
/**
|
||||
* Abstract base class for Hibernate UserType implementations that map to LOBs.
|
||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
||||
*
|
||||
* <p>For writing LOBs, either an active Spring transaction synchronization
|
||||
* or an active JTA transaction (with "jtaTransactionManager" specified on
|
||||
* LocalSessionFactoryBean or a Hibernate TransactionManagerLookup configured
|
||||
* through the corresponding Hibernate property) is required.
|
||||
*
|
||||
* <p>Offers template methods for setting parameters and getting result values,
|
||||
* passing in the LobHandler or LobCreator to use.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see org.springframework.jdbc.support.lob.LobHandler
|
||||
* @see org.springframework.jdbc.support.lob.LobCreator
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setJtaTransactionManager
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractLobType implements UserType {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final LobHandler lobHandler;
|
||||
|
||||
private final TransactionManager jtaTransactionManager;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
||||
*/
|
||||
protected AbstractLobType() {
|
||||
this(org.springframework.orm.hibernate3.LocalSessionFactoryBean.getConfigTimeLobHandler(),
|
||||
org.springframework.orm.hibernate3.LocalSessionFactoryBean.getConfigTimeTransactionManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used for testing: takes an explicit LobHandler
|
||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
||||
*/
|
||||
protected AbstractLobType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
||||
this.lobHandler = lobHandler;
|
||||
this.jtaTransactionManager = jtaTransactionManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation returns false.
|
||||
*/
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to the Hibernate EqualsHelper.
|
||||
* @see org.hibernate.util.EqualsHelper#equals
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object x, Object y) throws HibernateException {
|
||||
return EqualsHelper.equals(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the hashCode of the given objectz.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode(Object x) throws HibernateException {
|
||||
return x.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the passed-in value as-is.
|
||||
*/
|
||||
@Override
|
||||
public Object deepCopy(Object value) throws HibernateException {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the passed-in value as-is.
|
||||
*/
|
||||
@Override
|
||||
public Serializable disassemble(Object value) throws HibernateException {
|
||||
return (Serializable) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the passed-in value as-is.
|
||||
*/
|
||||
@Override
|
||||
public Object assemble(Serializable cached, Object owner) throws HibernateException {
|
||||
return cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the passed-in original as-is.
|
||||
*/
|
||||
@Override
|
||||
public Object replace(Object original, Object target, Object owner) throws HibernateException {
|
||||
return original;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation delegates to nullSafeGetInternal,
|
||||
* passing in the LobHandler of this type.
|
||||
* @see #nullSafeGetInternal
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public final Object nullSafeGet(ResultSet rs, String[] names, Object owner)
|
||||
throws HibernateException, SQLException {
|
||||
|
||||
if (this.lobHandler == null) {
|
||||
throw new IllegalStateException("No LobHandler found for configuration - " +
|
||||
"lobHandler property must be set on LocalSessionFactoryBean");
|
||||
}
|
||||
|
||||
try {
|
||||
return nullSafeGetInternal(rs, names, owner, this.lobHandler);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new HibernateException("I/O errors during LOB access", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to nullSafeSetInternal,
|
||||
* passing in a transaction-synchronized LobCreator for the
|
||||
* LobHandler of this type.
|
||||
* @see #nullSafeSetInternal
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public final void nullSafeSet(PreparedStatement st, Object value, int index)
|
||||
throws HibernateException, SQLException {
|
||||
|
||||
if (this.lobHandler == null) {
|
||||
throw new IllegalStateException("No LobHandler found for configuration - " +
|
||||
"lobHandler property must be set on LocalSessionFactoryBean");
|
||||
}
|
||||
|
||||
LobCreator lobCreator = this.lobHandler.getLobCreator();
|
||||
try {
|
||||
nullSafeSetInternal(st, index, value, lobCreator);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new HibernateException("I/O errors during LOB access", ex);
|
||||
}
|
||||
LobCreatorUtils.registerTransactionSynchronization(lobCreator, this.jtaTransactionManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method to extract a value from the given result set.
|
||||
* @param rs the ResultSet to extract from
|
||||
* @param names the column names
|
||||
* @param owner the containing entity
|
||||
* @param lobHandler the LobHandler to use
|
||||
* @return the extracted value
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @throws IOException if thrown by streaming methods
|
||||
* @throws HibernateException in case of any other exceptions
|
||||
*/
|
||||
protected abstract Object nullSafeGetInternal(
|
||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
||||
throws SQLException, IOException, HibernateException;
|
||||
|
||||
/**
|
||||
* Template method to set the given parameter value on the given statement.
|
||||
* @param ps the PreparedStatement to set on
|
||||
* @param index the statement parameter index
|
||||
* @param value the value to set
|
||||
* @param lobCreator the LobCreator to use
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @throws IOException if thrown by streaming methods
|
||||
* @throws HibernateException in case of any other exceptions
|
||||
*/
|
||||
protected abstract void nullSafeSetInternal(
|
||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
||||
throws SQLException, IOException, HibernateException;
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3.support;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.springframework.jdbc.support.lob.LobCreator;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
|
||||
/**
|
||||
* Hibernate UserType implementation for byte arrays that get mapped to BLOBs.
|
||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
||||
*
|
||||
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
|
||||
* work with most JDBC-compliant database drivers. In this case, the field type
|
||||
* does not have to be BLOB: For databases like MySQL and MS SQL Server, any
|
||||
* large enough binary type will work.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class BlobByteArrayType extends AbstractLobType {
|
||||
|
||||
/**
|
||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
||||
*/
|
||||
public BlobByteArrayType() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used for testing: takes an explicit LobHandler
|
||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
||||
*/
|
||||
protected BlobByteArrayType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
||||
super(lobHandler, jtaTransactionManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] sqlTypes() {
|
||||
return new int[] {Types.BLOB};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnedClass() {
|
||||
return byte[].class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object x, Object y) {
|
||||
return (x == y) ||
|
||||
(x instanceof byte[] && y instanceof byte[] && Arrays.equals((byte[]) x, (byte[]) y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object deepCopy(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] original = (byte[]) value;
|
||||
byte[] copy = new byte[original.length];
|
||||
System.arraycopy(original, 0, copy, 0, original.length);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nullSafeGetInternal(
|
||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
||||
throws SQLException {
|
||||
|
||||
return lobHandler.getBlobAsBytes(rs, names[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void nullSafeSetInternal(
|
||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
||||
throws SQLException {
|
||||
|
||||
lobCreator.setBlobAsBytes(ps, index, (byte[]) value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3.support;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
||||
import org.springframework.jdbc.support.lob.LobCreator;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
|
||||
/**
|
||||
* Hibernate UserType implementation for arbitrary objects that get serialized to BLOBs.
|
||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
||||
*
|
||||
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
|
||||
* work with most JDBC-compliant database drivers. In this case, the field type
|
||||
* does not have to be BLOB: For databases like MySQL and MS SQL Server, any
|
||||
* large enough binary type will work.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class BlobSerializableType extends AbstractLobType {
|
||||
|
||||
/**
|
||||
* Initial size for ByteArrayOutputStreams used for serialization output.
|
||||
* <p>If a serialized object is larger than these 1024 bytes, the size of
|
||||
* the byte array used by the output stream will be doubled each time the
|
||||
* limit is reached.
|
||||
*/
|
||||
private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
||||
*/
|
||||
public BlobSerializableType() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used for testing: takes an explicit LobHandler
|
||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
||||
*/
|
||||
protected BlobSerializableType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
||||
super(lobHandler, jtaTransactionManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] sqlTypes() {
|
||||
return new int[] {Types.BLOB};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnedClass() {
|
||||
return Serializable.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object deepCopy(Object value) throws HibernateException {
|
||||
try {
|
||||
// Write to new byte array to clone.
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
try {
|
||||
oos.writeObject(value);
|
||||
}
|
||||
finally {
|
||||
oos.close();
|
||||
}
|
||||
|
||||
// Read it back and return a true copy.
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
try {
|
||||
return ois.readObject();
|
||||
}
|
||||
finally {
|
||||
ois.close();
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new HibernateException("Couldn't clone BLOB contents", ex);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new HibernateException("Couldn't clone BLOB contents", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nullSafeGetInternal(
|
||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
||||
throws SQLException, IOException, HibernateException {
|
||||
|
||||
InputStream is = lobHandler.getBlobAsBinaryStream(rs, names[0]);
|
||||
if (is != null) {
|
||||
ObjectInputStream ois = new ObjectInputStream(is);
|
||||
try {
|
||||
return ois.readObject();
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new HibernateException("Could not deserialize BLOB contents", ex);
|
||||
}
|
||||
finally {
|
||||
ois.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void nullSafeSetInternal(
|
||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
||||
throws SQLException, IOException {
|
||||
|
||||
if (value != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
try {
|
||||
oos.writeObject(value);
|
||||
oos.flush();
|
||||
lobCreator.setBlobAsBytes(ps, index, baos.toByteArray());
|
||||
}
|
||||
finally {
|
||||
oos.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
lobCreator.setBlobAsBytes(ps, index, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3.support;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.springframework.jdbc.support.lob.LobCreator;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
|
||||
/**
|
||||
* Hibernate UserType implementation for Strings that get mapped to BLOBs.
|
||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
||||
*
|
||||
* <p>This is intended for the (arguably unnatural, but still common) case
|
||||
* where character data is stored in a binary LOB. This requires encoding
|
||||
* and decoding the characters within this UserType; see the javadoc of the
|
||||
* {@code getCharacterEncoding()} method.
|
||||
*
|
||||
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
|
||||
* work with most JDBC-compliant database drivers. In this case, the field type
|
||||
* does not have to be BLOB: For databases like MySQL and MS SQL Server, any
|
||||
* large enough binary type will work.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2.7
|
||||
* @see #getCharacterEncoding()
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class BlobStringType extends AbstractLobType {
|
||||
|
||||
/**
|
||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
||||
*/
|
||||
public BlobStringType() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used for testing: takes an explicit LobHandler
|
||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
||||
*/
|
||||
protected BlobStringType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
||||
super(lobHandler, jtaTransactionManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] sqlTypes() {
|
||||
return new int[] {Types.BLOB};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnedClass() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nullSafeGetInternal(
|
||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
||||
throws SQLException, UnsupportedEncodingException {
|
||||
|
||||
byte[] bytes = lobHandler.getBlobAsBytes(rs, names[0]);
|
||||
if (bytes != null) {
|
||||
String encoding = getCharacterEncoding();
|
||||
return (encoding != null ? new String(bytes, encoding) : new String(bytes));
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void nullSafeSetInternal(
|
||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
||||
throws SQLException, UnsupportedEncodingException {
|
||||
|
||||
if (value != null) {
|
||||
String str = (String) value;
|
||||
String encoding = getCharacterEncoding();
|
||||
byte[] bytes = (encoding != null ? str.getBytes(encoding) : str.getBytes());
|
||||
lobCreator.setBlobAsBytes(ps, index, bytes);
|
||||
}
|
||||
else {
|
||||
lobCreator.setBlobAsBytes(ps, index, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the character encoding to apply to the BLOB's bytes
|
||||
* to turn them into a String.
|
||||
* <p>Default is {@code null}, indicating to use the platform
|
||||
* default encoding. To be overridden in subclasses for a specific
|
||||
* encoding such as "ISO-8859-1" or "UTF-8".
|
||||
* @return the character encoding to use, or {@code null}
|
||||
* to use the platform default encoding
|
||||
* @see String#String(byte[], String)
|
||||
* @see String#getBytes(String)
|
||||
*/
|
||||
protected String getCharacterEncoding() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3.support;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.springframework.jdbc.support.lob.LobCreator;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
|
||||
/**
|
||||
* Hibernate UserType implementation for Strings that get mapped to CLOBs.
|
||||
* Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
|
||||
*
|
||||
* <p>Particularly useful for storing Strings with more than 4000 characters in an
|
||||
* Oracle database (only possible via CLOBs), in combination with OracleLobHandler.
|
||||
*
|
||||
* <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
|
||||
* work with most JDBC-compliant database drivers. In this case, the field type
|
||||
* does not have to be CLOB: For databases like MySQL and MS SQL Server, any
|
||||
* large enough character type will work.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class ClobStringType extends AbstractLobType {
|
||||
|
||||
/**
|
||||
* Constructor used by Hibernate: fetches config-time LobHandler and
|
||||
* config-time JTA TransactionManager from LocalSessionFactoryBean.
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
|
||||
*/
|
||||
public ClobStringType() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used for testing: takes an explicit LobHandler
|
||||
* and an explicit JTA TransactionManager (can be {@code null}).
|
||||
*/
|
||||
protected ClobStringType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
|
||||
super(lobHandler, jtaTransactionManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] sqlTypes() {
|
||||
return new int[] {Types.CLOB};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnedClass() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object nullSafeGetInternal(
|
||||
ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
|
||||
throws SQLException {
|
||||
|
||||
return lobHandler.getClobAsString(rs, names[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void nullSafeSetInternal(
|
||||
PreparedStatement ps, int index, Object value, LobCreator lobCreator)
|
||||
throws SQLException {
|
||||
|
||||
lobCreator.setClobAsString(ps, index, (String) value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.hibernate3.support;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.support.DaoSupport;
|
||||
|
||||
/**
|
||||
* Convenient super class for Hibernate-based data access objects.
|
||||
*
|
||||
* <p>Requires a {@link org.hibernate.SessionFactory} to be set, providing a
|
||||
* {@link org.springframework.orm.hibernate3.HibernateTemplate} based on it to
|
||||
* subclasses through the {@link #getHibernateTemplate()} method.
|
||||
* Can alternatively be initialized directly with a HibernateTemplate,
|
||||
* in order to reuse the latter's settings such as the SessionFactory,
|
||||
* exception translator, flush mode, etc.
|
||||
*
|
||||
* <p>This base class is mainly intended for HibernateTemplate usage but can
|
||||
* also be used when working with a Hibernate Session directly, for example
|
||||
* when relying on transactional Sessions. Convenience {@link #getSession}
|
||||
* and {@link #releaseSession} methods are provided for that usage style.
|
||||
*
|
||||
* <p>This class will create its own HibernateTemplate instance if a SessionFactory
|
||||
* is passed in. The "allowCreate" flag on that HibernateTemplate will be "true"
|
||||
* by default. A custom HibernateTemplate instance can be used through overriding
|
||||
* {@link #createHibernateTemplate}.
|
||||
*
|
||||
* <p><b>NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
|
||||
* also be coded in plain Hibernate style. Hence, for newly started projects,
|
||||
* consider adopting the standard Hibernate3 style of coding data access objects
|
||||
* instead, based on {@link org.hibernate.SessionFactory#getCurrentSession()}.</b>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see #setSessionFactory
|
||||
* @see #getHibernateTemplate
|
||||
* @see org.springframework.orm.hibernate3.HibernateTemplate
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class HibernateDaoSupport extends DaoSupport {
|
||||
|
||||
private org.springframework.orm.hibernate3.HibernateTemplate hibernateTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* Set the Hibernate SessionFactory to be used by this DAO.
|
||||
* Will automatically create a HibernateTemplate for the given SessionFactory.
|
||||
* @see #createHibernateTemplate
|
||||
* @see #setHibernateTemplate
|
||||
*/
|
||||
public final void setSessionFactory(SessionFactory sessionFactory) {
|
||||
if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
|
||||
this.hibernateTemplate = createHibernateTemplate(sessionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HibernateTemplate for the given SessionFactory.
|
||||
* Only invoked if populating the DAO with a SessionFactory reference!
|
||||
* <p>Can be overridden in subclasses to provide a HibernateTemplate instance
|
||||
* with different configuration, or a custom HibernateTemplate subclass.
|
||||
* @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for
|
||||
* @return the new HibernateTemplate instance
|
||||
* @see #setSessionFactory
|
||||
*/
|
||||
protected org.springframework.orm.hibernate3.HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
|
||||
return new org.springframework.orm.hibernate3.HibernateTemplate(sessionFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Hibernate SessionFactory used by this DAO.
|
||||
*/
|
||||
public final SessionFactory getSessionFactory() {
|
||||
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HibernateTemplate for this DAO explicitly,
|
||||
* as an alternative to specifying a SessionFactory.
|
||||
* @see #setSessionFactory
|
||||
*/
|
||||
public final void setHibernateTemplate(org.springframework.orm.hibernate3.HibernateTemplate hibernateTemplate) {
|
||||
this.hibernateTemplate = hibernateTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HibernateTemplate for this DAO,
|
||||
* pre-initialized with the SessionFactory or set explicitly.
|
||||
* <p><b>Note: The returned HibernateTemplate is a shared instance.</b>
|
||||
* You may introspect its configuration, but not modify the configuration
|
||||
* (other than from within an {@link #initDao} implementation).
|
||||
* Consider creating a custom HibernateTemplate instance via
|
||||
* {@code new HibernateTemplate(getSessionFactory())}, in which case
|
||||
* you're allowed to customize the settings on the resulting instance.
|
||||
*/
|
||||
public final org.springframework.orm.hibernate3.HibernateTemplate getHibernateTemplate() {
|
||||
return this.hibernateTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void checkDaoConfig() {
|
||||
if (this.hibernateTemplate == null) {
|
||||
throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a Hibernate Session, either from the current transaction or
|
||||
* a new one. The latter is only allowed if the
|
||||
* {@link org.springframework.orm.hibernate3.HibernateTemplate#setAllowCreate "allowCreate"}
|
||||
* setting of this bean's {@link #setHibernateTemplate HibernateTemplate} is "true".
|
||||
* <p><b>Note that this is not meant to be invoked from HibernateTemplate code
|
||||
* but rather just in plain Hibernate code.</b> Either rely on a thread-bound
|
||||
* Session or use it in combination with {@link #releaseSession}.
|
||||
* <p>In general, it is recommended to use HibernateTemplate, either with
|
||||
* the provided convenience operations or with a custom HibernateCallback
|
||||
* that provides you with a Session to work on. HibernateTemplate will care
|
||||
* for all resource management and for proper exception conversion.
|
||||
* @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 org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
|
||||
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
|
||||
*/
|
||||
@Deprecated
|
||||
protected final Session getSession() throws DataAccessResourceFailureException, IllegalStateException {
|
||||
return getSession(this.hibernateTemplate.isAllowCreate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a Hibernate Session, either from the current transaction or
|
||||
* a new one. The latter is only allowed if "allowCreate" is true.
|
||||
* <p><b>Note that this is not meant to be invoked from HibernateTemplate code
|
||||
* but rather just in plain Hibernate code.</b> Either rely on a thread-bound
|
||||
* Session or use it in combination with {@link #releaseSession}.
|
||||
* <p>In general, it is recommended to use
|
||||
* {@link #getHibernateTemplate() HibernateTemplate}, either with
|
||||
* the provided convenience operations or with a custom
|
||||
* {@link org.springframework.orm.hibernate3.HibernateCallback} that
|
||||
* provides you with a Session to work on. HibernateTemplate will care
|
||||
* for all resource management and for proper exception conversion.
|
||||
* @param allowCreate if a non-transactional Session should be created when no
|
||||
* transactional Session can be found for the current thread
|
||||
* @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 org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
|
||||
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
|
||||
*/
|
||||
@Deprecated
|
||||
protected final Session getSession(boolean allowCreate)
|
||||
throws DataAccessResourceFailureException, IllegalStateException {
|
||||
|
||||
return (!allowCreate ?
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(getSessionFactory(), false) :
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(
|
||||
getSessionFactory(),
|
||||
this.hibernateTemplate.getEntityInterceptor(),
|
||||
this.hibernateTemplate.getJdbcExceptionTranslator()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given HibernateException to an appropriate exception from the
|
||||
* {@code org.springframework.dao} hierarchy. Will automatically detect
|
||||
* wrapped SQLExceptions and convert them accordingly.
|
||||
* <p>Delegates to the
|
||||
* {@link org.springframework.orm.hibernate3.HibernateTemplate#convertHibernateAccessException}
|
||||
* method of this DAO's HibernateTemplate.
|
||||
* <p>Typically used in plain Hibernate code, in combination with
|
||||
* {@link #getSession} and {@link #releaseSession}.
|
||||
* @param ex HibernateException that occurred
|
||||
* @return the corresponding DataAccessException instance
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#convertHibernateAccessException
|
||||
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
|
||||
*/
|
||||
@Deprecated
|
||||
protected final DataAccessException convertHibernateAccessException(HibernateException ex) {
|
||||
return this.hibernateTemplate.convertHibernateAccessException(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the given Hibernate Session, created via this DAO's SessionFactory,
|
||||
* if it isn't bound to the thread (i.e. isn't a transactional Session).
|
||||
* <p>Typically used in plain Hibernate code, in combination with
|
||||
* {@link #getSession} and {@link #convertHibernateAccessException}.
|
||||
* @param session the Session to close
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#releaseSession
|
||||
* @deprecated as of Spring 3.2.7, in favor of {@link org.springframework.orm.hibernate3.HibernateTemplate} usage
|
||||
*/
|
||||
@Deprecated
|
||||
protected final void releaseSession(Session session) {
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.releaseSession(session, getSessionFactory());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.event.MergeEvent;
|
||||
import org.hibernate.event.def.DefaultMergeEventListener;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
* Extension of Hibernate's DefaultMergeEventListener, transferring the ids
|
||||
* of newly saved objects to the corresponding original objects (that are part
|
||||
* of the detached object graph passed into the {@code merge} method).
|
||||
*
|
||||
* <p>Transferring newly assigned ids to the original graph allows for continuing
|
||||
* to use the original object graph, despite merged copies being registered with
|
||||
* the current Hibernate Session. This is particularly useful for web applications
|
||||
* that might want to store an object graph and then render it in a web view,
|
||||
* with links that include the id of certain (potentially newly saved) objects.
|
||||
*
|
||||
* <p>The merge behavior given by this MergeEventListener is nearly identical
|
||||
* to TopLink's merge behavior. See PetClinic for an example, which relies on
|
||||
* ids being available for newly saved objects: the {@code HibernateClinic}
|
||||
* and {@code TopLinkClinic} DAO implementations both use straight merge
|
||||
* calls, with the Hibernate SessionFactory configuration specifying an
|
||||
* {@code IdTransferringMergeEventListener}.
|
||||
*
|
||||
* <p>Typically specified as entry for LocalSessionFactoryBean's "eventListeners"
|
||||
* map, with key "merge".
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setEventListeners(java.util.Map)
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings({"serial", "rawtypes"})
|
||||
public class IdTransferringMergeEventListener extends DefaultMergeEventListener {
|
||||
|
||||
/**
|
||||
* Hibernate 3.1 implementation of ID transferral.
|
||||
*/
|
||||
@Override
|
||||
protected void entityIsTransient(MergeEvent event, Map copyCache) {
|
||||
super.entityIsTransient(event, copyCache);
|
||||
SessionImplementor session = event.getSession();
|
||||
EntityPersister persister = session.getEntityPersister(event.getEntityName(), event.getEntity());
|
||||
// Extract id from merged copy (which is currently registered with Session).
|
||||
Serializable id = persister.getIdentifier(event.getResult(), session.getEntityMode());
|
||||
// Set id on original object (which remains detached).
|
||||
persister.setIdentifier(event.getOriginal(), id, session.getEntityMode());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.hibernate3.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
/**
|
||||
* Servlet Filter that binds a Hibernate Session to the thread for the entire
|
||||
* processing of the request. Intended for the "Open Session in View" pattern,
|
||||
* i.e. to allow for lazy loading in web views despite the original transactions
|
||||
* already being completed.
|
||||
*
|
||||
* <p>This filter makes Hibernate Sessions available via the current thread, which
|
||||
* will be autodetected by transaction managers. It is suitable for service layer
|
||||
* transactions via {@link org.springframework.orm.hibernate3.HibernateTransactionManager}
|
||||
* or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
|
||||
* as for non-transactional execution (if configured appropriately).
|
||||
*
|
||||
* <p><b>NOTE</b>: This filter will by default <i>not</i> flush the Hibernate Session,
|
||||
* with the flush mode set to {@code FlushMode.NEVER}. It assumes to be used
|
||||
* in combination with service layer transactions that care for the flushing: The
|
||||
* active transaction manager will temporarily change the flush mode to
|
||||
* {@code FlushMode.AUTO} during a read-write transaction, with the flush
|
||||
* mode reset to {@code FlushMode.NEVER} at the end of each transaction.
|
||||
* If you intend to use this filter without transactions, consider changing
|
||||
* the default flush mode (through the "flushMode" property).
|
||||
*
|
||||
* <p><b>WARNING:</b> Applying this filter to existing logic can cause issues that
|
||||
* have not appeared before, through the use of a single Hibernate Session for the
|
||||
* processing of an entire request. In particular, the reassociation of persistent
|
||||
* objects with a Hibernate Session has to occur at the very beginning of request
|
||||
* processing, to avoid clashes with already loaded instances of the same objects.
|
||||
*
|
||||
* <p>Alternatively, turn this filter into deferred close mode, by specifying
|
||||
* "singleSession"="false": It will not use a single session per request then,
|
||||
* but rather let each data access operation or transaction use its own session
|
||||
* (like without Open Session in View). Each of those sessions will be registered
|
||||
* for deferred close, though, actually processed at request completion.
|
||||
*
|
||||
* <p>A single session per request allows for most efficient first-level caching,
|
||||
* but can cause side effects, for example on {@code saveOrUpdate} or when
|
||||
* continuing after a rolled-back transaction. The deferred close strategy is as safe
|
||||
* as no Open Session in View in that respect, while still allowing for lazy loading
|
||||
* in views (but not providing a first-level cache for the entire request).
|
||||
*
|
||||
* <p>Looks up the SessionFactory in Spring's root web application context.
|
||||
* Supports a "sessionFactoryBeanName" filter init-param in {@code web.xml};
|
||||
* the default bean name is "sessionFactory".
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see #setSingleSession
|
||||
* @see #setFlushMode
|
||||
* @see #lookupSessionFactory
|
||||
* @see OpenSessionInViewInterceptor
|
||||
* @see OpenSessionInterceptor
|
||||
* @see org.springframework.orm.hibernate3.HibernateTransactionManager
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||
|
||||
public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
|
||||
|
||||
|
||||
private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
|
||||
|
||||
private boolean singleSession = true;
|
||||
|
||||
private FlushMode flushMode = FlushMode.MANUAL;
|
||||
|
||||
|
||||
/**
|
||||
* Set the bean name of the SessionFactory to fetch from Spring's
|
||||
* root application context. Default is "sessionFactory".
|
||||
* @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
|
||||
*/
|
||||
public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
|
||||
this.sessionFactoryBeanName = sessionFactoryBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean name of the SessionFactory to fetch from Spring's
|
||||
* root application context.
|
||||
*/
|
||||
protected String getSessionFactoryBeanName() {
|
||||
return this.sessionFactoryBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use a single session for each request. Default is "true".
|
||||
* <p>If set to "false", each data access operation or transaction will use
|
||||
* its own session (like without Open Session in View). Each of those
|
||||
* sessions will be registered for deferred close, though, actually
|
||||
* processed at request completion.
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#initDeferredClose
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#processDeferredClose
|
||||
*/
|
||||
public void setSingleSession(boolean singleSession) {
|
||||
this.singleSession = singleSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to use a single session for each request.
|
||||
*/
|
||||
protected boolean isSingleSession() {
|
||||
return this.singleSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the Hibernate FlushMode to apply to this filter's
|
||||
* {@link org.hibernate.Session}. Only applied in single session mode.
|
||||
* <p>Can be populated with the corresponding constant name in XML bean
|
||||
* definitions: e.g. "AUTO".
|
||||
* <p>The default is "MANUAL". Specify "AUTO" if you intend to use
|
||||
* this filter without service layer transactions.
|
||||
* @see org.hibernate.Session#setFlushMode
|
||||
* @see org.hibernate.FlushMode#MANUAL
|
||||
* @see org.hibernate.FlushMode#AUTO
|
||||
*/
|
||||
public void setFlushMode(FlushMode flushMode) {
|
||||
this.flushMode = flushMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Hibernate FlushMode that this filter applies to its
|
||||
* {@link org.hibernate.Session} (in single session mode).
|
||||
*/
|
||||
protected FlushMode getFlushMode() {
|
||||
return this.flushMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns "false" so that the filter may re-bind the opened Hibernate
|
||||
* {@code Session} to each asynchronously dispatched thread and postpone
|
||||
* closing it until the very last asynchronous dispatch.
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldNotFilterAsyncDispatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns "false" so that the filter may provide a Hibernate
|
||||
* {@code Session} to each error dispatches.
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldNotFilterErrorDispatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
SessionFactory sessionFactory = lookupSessionFactory(request);
|
||||
boolean participate = false;
|
||||
|
||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
||||
String key = getAlreadyFilteredAttributeName();
|
||||
|
||||
if (isSingleSession()) {
|
||||
// single session mode
|
||||
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
|
||||
// Do not modify the Session: just set the participate flag.
|
||||
participate = true;
|
||||
}
|
||||
else {
|
||||
boolean isFirstRequest = !isAsyncDispatch(request);
|
||||
if (isFirstRequest || !applySessionBindingInterceptor(asyncManager, key)) {
|
||||
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
|
||||
Session session = getSession(sessionFactory);
|
||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder = new org.springframework.orm.hibernate3.SessionHolder(session);
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||
|
||||
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
|
||||
asyncManager.registerCallableInterceptor(key, interceptor);
|
||||
asyncManager.registerDeferredResultInterceptor(key, interceptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// deferred close mode
|
||||
Assert.state(!isAsyncStarted(request), "Deferred close mode is not supported on async dispatches");
|
||||
if (org.springframework.orm.hibernate3.SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
|
||||
// Do not modify deferred close: just set the participate flag.
|
||||
participate = true;
|
||||
}
|
||||
else {
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.initDeferredClose(sessionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
finally {
|
||||
if (!participate) {
|
||||
if (isSingleSession()) {
|
||||
// single session mode
|
||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder =
|
||||
(org.springframework.orm.hibernate3.SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||
if (!isAsyncStarted(request)) {
|
||||
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
|
||||
closeSession(sessionHolder.getSession(), sessionFactory);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// deferred close mode
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.processDeferredClose(sessionFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the SessionFactory that this filter should use,
|
||||
* taking the current HTTP request as argument.
|
||||
* <p>The default implementation delegates to the {@link #lookupSessionFactory()}
|
||||
* variant without arguments.
|
||||
* @param request the current request
|
||||
* @return the SessionFactory to use
|
||||
*/
|
||||
protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
|
||||
return lookupSessionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the SessionFactory that this filter should use.
|
||||
* <p>The default implementation looks for a bean with the specified name
|
||||
* in Spring's root application context.
|
||||
* @return the SessionFactory to use
|
||||
* @see #getSessionFactoryBeanName
|
||||
*/
|
||||
protected SessionFactory lookupSessionFactory() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
|
||||
}
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
|
||||
return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Session for the SessionFactory that this filter uses.
|
||||
* Note that this just applies in single session mode!
|
||||
* <p>The default implementation delegates to the
|
||||
* {@code SessionFactoryUtils.getSession} method and
|
||||
* sets the {@code Session}'s flush mode to "MANUAL".
|
||||
* <p>Can be overridden in subclasses for creating a Session with a
|
||||
* custom entity interceptor or JDBC exception translator.
|
||||
* @param sessionFactory the SessionFactory that this filter uses
|
||||
* @return the Session to use
|
||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
|
||||
* @see org.hibernate.FlushMode#MANUAL
|
||||
*/
|
||||
protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
|
||||
Session session = org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(sessionFactory, true);
|
||||
FlushMode flushMode = getFlushMode();
|
||||
if (flushMode != null) {
|
||||
session.setFlushMode(flushMode);
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the given Session.
|
||||
* Note that this just applies in single session mode!
|
||||
* <p>Can be overridden in subclasses, e.g. for flushing the Session before
|
||||
* closing it. See class-level javadoc for a discussion of flush handling.
|
||||
* Note that you should also override getSession accordingly, to set
|
||||
* the flush mode to something else than NEVER.
|
||||
* @param session the Session used for filtering
|
||||
* @param sessionFactory the SessionFactory that this filter uses
|
||||
*/
|
||||
protected void closeSession(Session session, SessionFactory sessionFactory) {
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(session);
|
||||
}
|
||||
|
||||
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
|
||||
if (asyncManager.getCallableInterceptor(key) == null) {
|
||||
return false;
|
||||
}
|
||||
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.hibernate3.support;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
|
||||
/**
|
||||
* Spring web request interceptor that binds a Hibernate {@code Session} to the
|
||||
* thread for the entire processing of the request.
|
||||
*
|
||||
* <p>This class is a concrete expression of the "Open Session in View" pattern, which
|
||||
* is a pattern that allows for the lazy loading of associations in web views despite
|
||||
* the original transactions already being completed.
|
||||
*
|
||||
* <p>This interceptor makes Hibernate {@code Sessions} available via the current
|
||||
* thread, which will be autodetected by transaction managers. It is suitable for
|
||||
* service layer transactions via
|
||||
* {@link org.springframework.orm.hibernate3.HibernateTransactionManager} or
|
||||
* {@link org.springframework.transaction.jta.JtaTransactionManager} as well as for
|
||||
* non-transactional execution (if configured appropriately).
|
||||
*
|
||||
* <p><b>NOTE</b>: This interceptor will by default <i>not</i> flush the Hibernate
|
||||
* {@code Session}, with the flush mode being set to {@code FlushMode.NEVER}.
|
||||
* It assumes that it will be used in combination with service layer transactions
|
||||
* that handle the flushing: the active transaction manager will temporarily change
|
||||
* the flush mode to {@code FlushMode.AUTO} during a read-write transaction,
|
||||
* with the flush mode reset to {@code FlushMode.NEVER} at the end of each
|
||||
* transaction. If you intend to use this interceptor without transactions, consider
|
||||
* changing the default flush mode (through the
|
||||
* {@link #setFlushMode(int) "flushMode"} property).
|
||||
*
|
||||
* <p>In contrast to {@link OpenSessionInViewFilter}, this interceptor is
|
||||
* configured in a Spring application context and can thus take advantage of bean
|
||||
* wiring. It inherits common Hibernate configuration properties from
|
||||
* {@link org.springframework.orm.hibernate3.HibernateAccessor},
|
||||
* to be configured in a bean definition.
|
||||
*
|
||||
* <p><b>WARNING:</b> Applying this interceptor to existing logic can cause issues
|
||||
* that have not appeared before, through the use of a single Hibernate
|
||||
* {@code Session} for the processing of an entire request. In particular, the
|
||||
* reassociation of persistent objects with a Hibernate {@code Session} has to
|
||||
* occur at the very beginning of request processing, to avoid clashes with already
|
||||
* loaded instances of the same objects.
|
||||
*
|
||||
* <p>Alternatively, turn this interceptor into deferred close mode, by specifying
|
||||
* "singleSession"="false": It will not use a single session per request then,
|
||||
* but rather let each data access operation or transaction use its own session
|
||||
* (as would be the case without Open Session in View). Each of those sessions will
|
||||
* be registered for deferred close though, which will actually be processed at
|
||||
* request completion.
|
||||
*
|
||||
* <p>A single session per request allows for the most efficient first-level caching,
|
||||
* but can cause side effects, for example on {@code saveOrUpdate} or when
|
||||
* continuing after a rolled-back transaction. The deferred close strategy is as safe
|
||||
* as no Open Session in View in that respect, while still allowing for lazy loading
|
||||
* in views (but not providing a first-level cache for the entire request).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see #setSingleSession
|
||||
* @see #setFlushMode
|
||||
* @see OpenSessionInViewFilter
|
||||
* @see OpenSessionInterceptor
|
||||
* @see org.springframework.orm.hibernate3.HibernateTransactionManager
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class OpenSessionInViewInterceptor extends org.springframework.orm.hibernate3.HibernateAccessor implements AsyncWebRequestInterceptor {
|
||||
|
||||
/**
|
||||
* Suffix that gets appended to the {@code SessionFactory}
|
||||
* {@code toString()} representation for the "participate in existing
|
||||
* session handling" request attribute.
|
||||
* @see #getParticipateAttributeName
|
||||
*/
|
||||
public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
|
||||
|
||||
|
||||
private boolean singleSession = true;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code OpenSessionInViewInterceptor},
|
||||
* turning the default flushMode to {@code FLUSH_NEVER}.
|
||||
* @see #setFlushMode
|
||||
*/
|
||||
public OpenSessionInViewInterceptor() {
|
||||
setFlushMode(FLUSH_NEVER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use a single session for each request. Default is "true".
|
||||
* <p>If set to false, each data access operation or transaction will use
|
||||
* its own session (like without Open Session in View). Each of those
|
||||
* sessions will be registered for deferred close, though, actually
|
||||
* processed at request completion.
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#initDeferredClose
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#processDeferredClose
|
||||
*/
|
||||
public void setSingleSession(boolean singleSession) {
|
||||
this.singleSession = singleSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to use a single session for each request.
|
||||
*/
|
||||
protected boolean isSingleSession() {
|
||||
return singleSession;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open a new Hibernate {@code Session} according to the settings of this
|
||||
* {@code HibernateAccessor} and bind it to the thread via the
|
||||
* {@link TransactionSynchronizationManager}.
|
||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
|
||||
*/
|
||||
@Override
|
||||
public void preHandle(WebRequest request) throws DataAccessException {
|
||||
String participateAttributeName = getParticipateAttributeName();
|
||||
|
||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
||||
if (asyncManager.hasConcurrentResult()) {
|
||||
if (applySessionBindingInterceptor(asyncManager, participateAttributeName)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((isSingleSession() && TransactionSynchronizationManager.hasResource(getSessionFactory())) ||
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.isDeferredCloseActive(getSessionFactory())) {
|
||||
// Do not modify the Session: just mark the request accordingly.
|
||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
||||
int newCount = (count != null ? count + 1 : 1);
|
||||
request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST);
|
||||
}
|
||||
else {
|
||||
if (isSingleSession()) {
|
||||
// single session mode
|
||||
logger.debug("Opening single Hibernate Session in OpenSessionInViewInterceptor");
|
||||
Session session = org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(
|
||||
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
|
||||
applyFlushMode(session, false);
|
||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder = new org.springframework.orm.hibernate3.SessionHolder(session);
|
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||
|
||||
AsyncRequestInterceptor asyncRequestInterceptor =
|
||||
new AsyncRequestInterceptor(getSessionFactory(), sessionHolder);
|
||||
asyncManager.registerCallableInterceptor(participateAttributeName, asyncRequestInterceptor);
|
||||
asyncManager.registerDeferredResultInterceptor(participateAttributeName, asyncRequestInterceptor);
|
||||
}
|
||||
else {
|
||||
// deferred close mode
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.initDeferredClose(getSessionFactory());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the Hibernate {@code Session} before view rendering, if necessary.
|
||||
* <p>Note that this just applies in {@link #isSingleSession() single session mode}!
|
||||
* <p>The default is {@code FLUSH_NEVER} to avoid this extra flushing,
|
||||
* assuming that service layer transactions have flushed their changes on commit.
|
||||
* @see #setFlushMode
|
||||
*/
|
||||
@Override
|
||||
public void postHandle(WebRequest request, ModelMap model) throws DataAccessException {
|
||||
if (isSingleSession()) {
|
||||
// Only potentially flush in single session mode.
|
||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder =
|
||||
(org.springframework.orm.hibernate3.SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
||||
logger.debug("Flushing single Hibernate Session in OpenSessionInViewInterceptor");
|
||||
try {
|
||||
flushIfNecessary(sessionHolder.getSession(), false);
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw convertHibernateAccessException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind the Hibernate {@code Session} from the thread and close it (in
|
||||
* single session mode), or process deferred close for all sessions that have
|
||||
* been opened during the current request (in deferred close mode).
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
*/
|
||||
@Override
|
||||
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
|
||||
if (!decrementParticipateCount(request)) {
|
||||
if (isSingleSession()) {
|
||||
// single session mode
|
||||
org.springframework.orm.hibernate3.SessionHolder sessionHolder =
|
||||
(org.springframework.orm.hibernate3.SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
||||
logger.debug("Closing single Hibernate Session in OpenSessionInViewInterceptor");
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
||||
}
|
||||
else {
|
||||
// deferred close mode
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.processDeferredClose(getSessionFactory());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConcurrentHandlingStarted(WebRequest request) {
|
||||
if (!decrementParticipateCount(request)) {
|
||||
if (isSingleSession()) {
|
||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Deferred close mode is not supported with async requests.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean decrementParticipateCount(WebRequest request) {
|
||||
String participateAttributeName = getParticipateAttributeName();
|
||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
||||
if (count == null) {
|
||||
return false;
|
||||
}
|
||||
// Do not modify the Session: just clear the marker.
|
||||
if (count > 1) {
|
||||
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST);
|
||||
}
|
||||
else {
|
||||
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the request attribute that identifies that a request is
|
||||
* already intercepted.
|
||||
* <p>The default implementation takes the {@code toString()} representation
|
||||
* of the {@code SessionFactory} instance and appends {@link #PARTICIPATE_SUFFIX}.
|
||||
*/
|
||||
protected String getParticipateAttributeName() {
|
||||
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
|
||||
}
|
||||
|
||||
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
|
||||
if (asyncManager.getCallableInterceptor(key) == null) {
|
||||
return false;
|
||||
}
|
||||
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.hibernate3.support;
|
||||
|
||||
import org.hibernate.EmptyInterceptor;
|
||||
|
||||
import org.springframework.aop.scope.ScopedObject;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
|
||||
/**
|
||||
* Hibernate3 interceptor used for getting the proper entity name for scoped
|
||||
* beans. As scoped bean classes are proxies generated at runtime, they are
|
||||
* unrecognized by the persisting framework. Using this interceptor, the
|
||||
* original scoped bean class is retrieved end exposed to Hibernate for
|
||||
* persisting.
|
||||
*
|
||||
* <p>Usage example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
|
||||
* ...
|
||||
* <property name="entityInterceptor">
|
||||
* <bean class="org.springframework.orm.hibernate3.support.ScopedBeanInterceptor"/>
|
||||
* </property>
|
||||
* </bean></pre>
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("serial")
|
||||
public class ScopedBeanInterceptor extends EmptyInterceptor {
|
||||
|
||||
@Override
|
||||
public String getEntityName(Object entity) {
|
||||
if (entity instanceof ScopedObject) {
|
||||
// Determine underlying object's type.
|
||||
Object targetObject = ((ScopedObject) entity).getTargetObject();
|
||||
return AopUtils.getTargetClass(targetObject).getName();
|
||||
}
|
||||
|
||||
// Any other object: delegate to the default implementation.
|
||||
return super.getEntityName(entity);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* Classes supporting the {@code org.springframework.orm.hibernate3} package.
|
||||
* Contains a DAO base class for HibernateTemplate usage.
|
||||
*/
|
||||
package org.springframework.orm.hibernate3.support;
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.hibernate5;
|
||||
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.Synchronization;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.TransactionSynchronizationRegistry;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.hibernate.TransactionException;
|
||||
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
|
||||
|
||||
import org.springframework.transaction.jta.UserTransactionAdapter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of Hibernate 5's JtaPlatform SPI, exposing passed-in {@link TransactionManager},
|
||||
* {@link UserTransaction} and {@link TransactionSynchronizationRegistry} references.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
class ConfigurableJtaPlatform implements JtaPlatform {
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final UserTransaction userTransaction;
|
||||
|
||||
private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ConfigurableJtaPlatform instance with the given
|
||||
* JTA TransactionManager and optionally a given UserTransaction.
|
||||
* @param tm the JTA TransactionManager reference (required)
|
||||
* @param ut the JTA UserTransaction reference (optional)
|
||||
* @param tsr the JTA 1.1 TransactionSynchronizationRegistry (optional)
|
||||
*/
|
||||
public ConfigurableJtaPlatform(TransactionManager tm, UserTransaction ut, TransactionSynchronizationRegistry tsr) {
|
||||
Assert.notNull(tm, "TransactionManager reference must not be null");
|
||||
this.transactionManager = tm;
|
||||
this.userTransaction = (ut != null ? ut : new UserTransactionAdapter(tm));
|
||||
this.transactionSynchronizationRegistry = tsr;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TransactionManager retrieveTransactionManager() {
|
||||
return this.transactionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserTransaction retrieveUserTransaction() {
|
||||
return this.userTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTransactionIdentifier(Transaction transaction) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRegisterSynchronization() {
|
||||
try {
|
||||
return (this.transactionManager.getStatus() == Status.STATUS_ACTIVE);
|
||||
}
|
||||
catch (SystemException ex) {
|
||||
throw new TransactionException("Could not determine JTA transaction status", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSynchronization(Synchronization synchronization) {
|
||||
if (this.transactionSynchronizationRegistry != null) {
|
||||
this.transactionSynchronizationRegistry.registerInterposedSynchronization(synchronization);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
this.transactionManager.getTransaction().registerSynchronization(synchronization);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new TransactionException("Could not access JTA Transaction to register synchronization", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentStatus() throws SystemException {
|
||||
return this.transactionManager.getStatus();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,9 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
|
||||
import java.sql.SQLException;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
@@ -25,35 +23,19 @@ import org.hibernate.Session;
|
||||
* Callback interface for Hibernate code. To be used with {@link HibernateTemplate}'s
|
||||
* execution methods, often as anonymous classes within a method implementation.
|
||||
* A typical implementation will call {@code Session.load/find/update} to perform
|
||||
* some operations on persistent objects. It can also perform direct JDBC operations
|
||||
* via Hibernate's {@code Session.connection()}, operating on a JDBC Connection.
|
||||
*
|
||||
* <p>Note that Hibernate works on unmodified plain Java objects, performing dirty
|
||||
* detection via copies made at load time. Returned objects can thus be used outside
|
||||
* of an active Hibernate Session without any hassle, e.g. for display in a web GUI.
|
||||
* Reassociating such instances with a new Session, e.g. for updates when coming
|
||||
* back from the GUI, is straightforward, as the instance has kept its identity.
|
||||
* You should care to reassociate them as early as possible though, to avoid having
|
||||
* already loaded a version from the database in the same Session.
|
||||
* some operations on persistent objects.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @since 4.2
|
||||
* @see HibernateTemplate
|
||||
* @see HibernateTransactionManager
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public interface HibernateCallback<T> {
|
||||
|
||||
/**
|
||||
* Gets called by {@code HibernateTemplate.execute} with an active
|
||||
* Hibernate {@code Session}. Does not need to care about activating
|
||||
* or closing the {@code Session}, or handling transactions.
|
||||
* <p>If called without a thread-bound Hibernate transaction (initiated
|
||||
* by HibernateTransactionManager), the code will simply get executed on the
|
||||
* underlying JDBC connection with its transactional semantics. If Hibernate
|
||||
* is configured to use a JTA-aware DataSource, the JDBC connection and thus
|
||||
* the callback code will be transactional if a JTA transaction is active.
|
||||
* <p>Allows for returning a result object created within the callback,
|
||||
* i.e. a domain object or a collection of domain objects.
|
||||
* A thrown custom RuntimeException is treated as an application exception:
|
||||
@@ -61,10 +43,8 @@ public interface HibernateCallback<T> {
|
||||
* @param session active Hibernate session
|
||||
* @return a result object, or {@code null} if none
|
||||
* @throws HibernateException if thrown by the Hibernate API
|
||||
* @throws SQLException if thrown by Hibernate-exposed JDBC API
|
||||
* @see HibernateTemplate#execute
|
||||
* @see HibernateTemplate#executeFind
|
||||
*/
|
||||
T doInHibernate(Session session) throws HibernateException, SQLException;
|
||||
T doInHibernate(Session session) throws HibernateException;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -14,14 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.JDBCException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
||||
|
||||
/**
|
||||
* {@link PersistenceExceptionTranslator} capable of translating {@link HibernateException}
|
||||
@@ -34,37 +32,12 @@ import org.springframework.jdbc.support.SQLExceptionTranslator;
|
||||
* of this type must be registered manually.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @since 4.2
|
||||
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException(HibernateException)
|
||||
* @see SQLExceptionTranslator
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public class HibernateExceptionTranslator implements PersistenceExceptionTranslator {
|
||||
|
||||
private SQLExceptionTranslator jdbcExceptionTranslator;
|
||||
|
||||
|
||||
/**
|
||||
* Set the JDBC exception translator for the SessionFactory,
|
||||
* exposed via the PersistenceExceptionTranslator interface.
|
||||
* <p>Applied to any SQLException root cause of a Hibernate JDBCException,
|
||||
* overriding Hibernate's default SQLException translation (which is
|
||||
* based on Hibernate's Dialect for a specific target database).
|
||||
* @param jdbcExceptionTranslator the exception translator
|
||||
* @see java.sql.SQLException
|
||||
* @see org.hibernate.JDBCException
|
||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
|
||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator
|
||||
*/
|
||||
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
|
||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
if (ex instanceof HibernateException) {
|
||||
@@ -76,19 +49,11 @@ public class HibernateExceptionTranslator implements PersistenceExceptionTransla
|
||||
/**
|
||||
* Convert the given HibernateException to an appropriate exception from the
|
||||
* {@code org.springframework.dao} hierarchy.
|
||||
* <p>Will automatically apply a specified SQLExceptionTranslator to a
|
||||
* Hibernate JDBCException, else rely on Hibernate's default translation.
|
||||
* @param ex HibernateException that occured
|
||||
* @return a corresponding DataAccessException
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
||||
* @see #setJdbcExceptionTranslator
|
||||
*/
|
||||
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
|
||||
if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
|
||||
JDBCException jdbcEx = (JDBCException) ex;
|
||||
return this.jdbcExceptionTranslator.translate(
|
||||
"Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
|
||||
}
|
||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -27,11 +27,9 @@ import org.springframework.dao.UncategorizedDataAccessException;
|
||||
* for JDBC exceptions that Hibernate wrapped.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @since 4.2
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateJdbcException extends UncategorizedDataAccessException {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.WrongClassException;
|
||||
@@ -26,11 +26,9 @@ import org.springframework.orm.ObjectRetrievalFailureException;
|
||||
* Converts Hibernate's UnresolvableObjectException and WrongClassException.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @since 4.2
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
@@ -38,33 +38,12 @@ import org.springframework.dao.DataAccessException;
|
||||
* strongly encouraged to read the Hibernate {@code Session} javadocs
|
||||
* for details on the semantics of those methods.
|
||||
*
|
||||
* <p>Note that operations that return an {@link java.util.Iterator} (i.e.
|
||||
* {@code iterate(..)}) are supposed to be used within Spring-driven
|
||||
* or JTA-driven transactions (with {@link HibernateTransactionManager},
|
||||
* {@link org.springframework.transaction.jta.JtaTransactionManager},
|
||||
* or EJB CMT). Else, the {@code Iterator} won't be able to read
|
||||
* results from its {@link java.sql.ResultSet} anymore, as the underlying
|
||||
* Hibernate {@code Session} will already have been closed.
|
||||
*
|
||||
* <p>Note that lazy loading will just work with an open Hibernate
|
||||
* {@code Session}, either within a transaction or within
|
||||
* {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter}/
|
||||
* {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}.
|
||||
* Furthermore, some operations just make sense within transactions,
|
||||
* for example: {@code contains}, {@code evict}, {@code lock},
|
||||
* {@code flush}, {@code clear}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @since 4.2
|
||||
* @see HibernateTemplate
|
||||
* @see org.hibernate.Session
|
||||
* @see HibernateTransactionManager
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
public interface HibernateOperations {
|
||||
|
||||
/**
|
||||
@@ -81,26 +60,12 @@ public interface HibernateOperations {
|
||||
* disconnect, or reconnect, to let the template do its work.
|
||||
* @param action callback object that specifies the Hibernate action
|
||||
* @return a result object returned by the action, or {@code null}
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see HibernateTransactionManager
|
||||
* @see org.hibernate.Session
|
||||
*/
|
||||
<T> T execute(HibernateCallback<T> action) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the specified action assuming that the result object is a
|
||||
* {@link List}.
|
||||
* <p>This is a convenience method for executing Hibernate find calls or
|
||||
* queries within an action.
|
||||
* @param action callback object that specifies the Hibernate action
|
||||
* @return a List result returned by the action, or {@code null}
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @deprecated as of Spring 3.2.7, in favor of using a regular {@link #execute}
|
||||
* call with a generic List type declared
|
||||
*/
|
||||
@Deprecated
|
||||
List<?> executeFind(HibernateCallback<?> action) throws DataAccessException;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Convenience methods for loading individual objects
|
||||
@@ -110,14 +75,14 @@ public interface HibernateOperations {
|
||||
* Return the persistent instance of the given entity class
|
||||
* with the given identifier, or {@code null} if not found.
|
||||
* <p>This method is a thin wrapper around
|
||||
* {@link org.hibernate.Session#get(Class, java.io.Serializable)} for convenience.
|
||||
* {@link org.hibernate.Session#get(Class, Serializable)} for convenience.
|
||||
* For an explanation of the exact semantics of this method, please do refer to
|
||||
* the Hibernate API documentation in the first instance.
|
||||
* @param entityClass a persistent class
|
||||
* @param id the identifier of the persistent instance
|
||||
* @return the persistent instance, or {@code null} if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#get(Class, java.io.Serializable)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#get(Class, Serializable)
|
||||
*/
|
||||
<T> T get(Class<T> entityClass, Serializable id) throws DataAccessException;
|
||||
|
||||
@@ -126,15 +91,15 @@ public interface HibernateOperations {
|
||||
* with the given identifier, or {@code null} if not found.
|
||||
* <p>Obtains the specified lock mode if the instance exists.
|
||||
* <p>This method is a thin wrapper around
|
||||
* {@link org.hibernate.Session#get(Class, java.io.Serializable, LockMode)} for convenience.
|
||||
* {@link org.hibernate.Session#get(Class, Serializable, LockMode)} for convenience.
|
||||
* For an explanation of the exact semantics of this method, please do refer to
|
||||
* the Hibernate API documentation in the first instance.
|
||||
* @param entityClass a persistent class
|
||||
* @param id the identifier of the persistent instance
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @return the persistent instance, or {@code null} if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#get(Class, Serializable, LockMode)
|
||||
*/
|
||||
<T> T get(Class<T> entityClass, Serializable id, LockMode lockMode) throws DataAccessException;
|
||||
|
||||
@@ -142,14 +107,14 @@ public interface HibernateOperations {
|
||||
* Return the persistent instance of the given entity class
|
||||
* with the given identifier, or {@code null} if not found.
|
||||
* <p>This method is a thin wrapper around
|
||||
* {@link org.hibernate.Session#get(String, java.io.Serializable)} for convenience.
|
||||
* {@link org.hibernate.Session#get(String, Serializable)} for convenience.
|
||||
* For an explanation of the exact semantics of this method, please do refer to
|
||||
* the Hibernate API documentation in the first instance.
|
||||
* @param entityName the name of the persistent entity
|
||||
* @param id the identifier of the persistent instance
|
||||
* @return the persistent instance, or {@code null} if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#get(Class, java.io.Serializable)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#get(Class, Serializable)
|
||||
*/
|
||||
Object get(String entityName, Serializable id) throws DataAccessException;
|
||||
|
||||
@@ -158,15 +123,15 @@ public interface HibernateOperations {
|
||||
* with the given identifier, or {@code null} if not found.
|
||||
* Obtains the specified lock mode if the instance exists.
|
||||
* <p>This method is a thin wrapper around
|
||||
* {@link org.hibernate.Session#get(String, java.io.Serializable, LockMode)} for convenience.
|
||||
* {@link org.hibernate.Session#get(String, Serializable, LockMode)} for convenience.
|
||||
* For an explanation of the exact semantics of this method, please do refer to
|
||||
* the Hibernate API documentation in the first instance.
|
||||
* @param entityName the name of the persistent entity
|
||||
* @param id the identifier of the persistent instance
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @return the persistent instance, or {@code null} if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#get(Class, Serializable, LockMode)
|
||||
*/
|
||||
Object get(String entityName, Serializable id, LockMode lockMode) throws DataAccessException;
|
||||
|
||||
@@ -174,15 +139,15 @@ public interface HibernateOperations {
|
||||
* Return the persistent instance of the given entity class
|
||||
* with the given identifier, throwing an exception if not found.
|
||||
* <p>This method is a thin wrapper around
|
||||
* {@link org.hibernate.Session#load(Class, java.io.Serializable)} for convenience.
|
||||
* {@link org.hibernate.Session#load(Class, Serializable)} for convenience.
|
||||
* For an explanation of the exact semantics of this method, please do refer to
|
||||
* the Hibernate API documentation in the first instance.
|
||||
* @param entityClass a persistent class
|
||||
* @param id the identifier of the persistent instance
|
||||
* @return the persistent instance
|
||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Class, Serializable)
|
||||
*/
|
||||
<T> T load(Class<T> entityClass, Serializable id) throws DataAccessException;
|
||||
|
||||
@@ -191,7 +156,7 @@ public interface HibernateOperations {
|
||||
* with the given identifier, throwing an exception if not found.
|
||||
* Obtains the specified lock mode if the instance exists.
|
||||
* <p>This method is a thin wrapper around
|
||||
* {@link org.hibernate.Session#load(Class, java.io.Serializable, LockMode)} for convenience.
|
||||
* {@link org.hibernate.Session#load(Class, Serializable, LockMode)} for convenience.
|
||||
* For an explanation of the exact semantics of this method, please do refer to
|
||||
* the Hibernate API documentation in the first instance.
|
||||
* @param entityClass a persistent class
|
||||
@@ -199,8 +164,8 @@ public interface HibernateOperations {
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @return the persistent instance
|
||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Class, Serializable)
|
||||
*/
|
||||
<T> T load(Class<T> entityClass, Serializable id, LockMode lockMode) throws DataAccessException;
|
||||
|
||||
@@ -208,15 +173,15 @@ public interface HibernateOperations {
|
||||
* Return the persistent instance of the given entity class
|
||||
* with the given identifier, throwing an exception if not found.
|
||||
* <p>This method is a thin wrapper around
|
||||
* {@link org.hibernate.Session#load(String, java.io.Serializable)} for convenience.
|
||||
* {@link org.hibernate.Session#load(String, Serializable)} for convenience.
|
||||
* For an explanation of the exact semantics of this method, please do refer to
|
||||
* the Hibernate API documentation in the first instance.
|
||||
* @param entityName the name of the persistent entity
|
||||
* @param id the identifier of the persistent instance
|
||||
* @return the persistent instance
|
||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Class, Serializable)
|
||||
*/
|
||||
Object load(String entityName, Serializable id) throws DataAccessException;
|
||||
|
||||
@@ -225,7 +190,7 @@ public interface HibernateOperations {
|
||||
* with the given identifier, throwing an exception if not found.
|
||||
* <p>Obtains the specified lock mode if the instance exists.
|
||||
* <p>This method is a thin wrapper around
|
||||
* {@link org.hibernate.Session#load(String, java.io.Serializable, LockMode)} for convenience.
|
||||
* {@link org.hibernate.Session#load(String, Serializable, LockMode)} for convenience.
|
||||
* For an explanation of the exact semantics of this method, please do refer to
|
||||
* the Hibernate API documentation in the first instance.
|
||||
* @param entityName the name of the persistent entity
|
||||
@@ -233,8 +198,8 @@ public interface HibernateOperations {
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @return the persistent instance
|
||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Class, java.io.Serializable)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Class, Serializable)
|
||||
*/
|
||||
Object load(String entityName, Serializable id, LockMode lockMode) throws DataAccessException;
|
||||
|
||||
@@ -243,7 +208,7 @@ public interface HibernateOperations {
|
||||
* Note: Use queries or criteria for retrieving a specific subset.
|
||||
* @param entityClass a persistent class
|
||||
* @return a {@link List} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException if there is a Hibernate error
|
||||
* @throws DataAccessException if there is a Hibernate error
|
||||
* @see org.hibernate.Session#createCriteria
|
||||
*/
|
||||
<T> List<T> loadAll(Class<T> entityClass) throws DataAccessException;
|
||||
@@ -252,21 +217,21 @@ public interface HibernateOperations {
|
||||
* Load the persistent instance with the given identifier
|
||||
* into the given object, throwing an exception if not found.
|
||||
* <p>This method is a thin wrapper around
|
||||
* {@link org.hibernate.Session#load(Object, java.io.Serializable)} for convenience.
|
||||
* {@link org.hibernate.Session#load(Object, Serializable)} for convenience.
|
||||
* For an explanation of the exact semantics of this method, please do refer to
|
||||
* the Hibernate API documentation in the first instance.
|
||||
* @param entity the object (of the target class) to load into
|
||||
* @param id the identifier of the persistent instance
|
||||
* @throws org.springframework.orm.ObjectRetrievalFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Object, java.io.Serializable)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#load(Object, Serializable)
|
||||
*/
|
||||
void load(Object entity, Serializable id) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Re-read the state of the given persistent instance.
|
||||
* @param entity the persistent instance to re-read
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#refresh(Object)
|
||||
*/
|
||||
void refresh(Object entity) throws DataAccessException;
|
||||
@@ -276,8 +241,8 @@ public interface HibernateOperations {
|
||||
* Obtains the specified lock mode for the instance.
|
||||
* @param entity the persistent instance to re-read
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#refresh(Object, org.hibernate.LockMode)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#refresh(Object, LockMode)
|
||||
*/
|
||||
void refresh(Object entity, LockMode lockMode) throws DataAccessException;
|
||||
|
||||
@@ -285,7 +250,7 @@ public interface HibernateOperations {
|
||||
* Check whether the given object is in the Session cache.
|
||||
* @param entity the persistence instance to check
|
||||
* @return whether the given object is in the Session cache
|
||||
* @throws org.springframework.dao.DataAccessException if there is a Hibernate error
|
||||
* @throws DataAccessException if there is a Hibernate error
|
||||
* @see org.hibernate.Session#contains
|
||||
*/
|
||||
boolean contains(Object entity) throws DataAccessException;
|
||||
@@ -293,7 +258,7 @@ public interface HibernateOperations {
|
||||
/**
|
||||
* Remove the given object from the {@link org.hibernate.Session} cache.
|
||||
* @param entity the persistent instance to evict
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#evict
|
||||
*/
|
||||
void evict(Object entity) throws DataAccessException;
|
||||
@@ -329,8 +294,8 @@ public interface HibernateOperations {
|
||||
* @param entity the persistent instance to lock
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#lock(Object, org.hibernate.LockMode)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#lock(Object, LockMode)
|
||||
*/
|
||||
void lock(Object entity, LockMode lockMode) throws DataAccessException;
|
||||
|
||||
@@ -341,8 +306,8 @@ public interface HibernateOperations {
|
||||
* @param entity the persistent instance to lock
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#lock(String, Object, org.hibernate.LockMode)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#lock(String, Object, LockMode)
|
||||
*/
|
||||
void lock(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
|
||||
|
||||
@@ -350,7 +315,7 @@ public interface HibernateOperations {
|
||||
* Persist the given transient instance.
|
||||
* @param entity the transient instance to persist
|
||||
* @return the generated identifier
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#save(Object)
|
||||
*/
|
||||
Serializable save(Object entity) throws DataAccessException;
|
||||
@@ -360,7 +325,7 @@ public interface HibernateOperations {
|
||||
* @param entityName the name of the persistent entity
|
||||
* @param entity the transient instance to persist
|
||||
* @return the generated identifier
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#save(String, Object)
|
||||
*/
|
||||
Serializable save(String entityName, Object entity) throws DataAccessException;
|
||||
@@ -369,7 +334,7 @@ public interface HibernateOperations {
|
||||
* Update the given persistent instance,
|
||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
||||
* @param entity the persistent instance to update
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#update(Object)
|
||||
*/
|
||||
void update(Object entity) throws DataAccessException;
|
||||
@@ -382,7 +347,7 @@ public interface HibernateOperations {
|
||||
* @param entity the persistent instance to update
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#update(Object)
|
||||
*/
|
||||
void update(Object entity, LockMode lockMode) throws DataAccessException;
|
||||
@@ -392,7 +357,7 @@ public interface HibernateOperations {
|
||||
* associating it with the current Hibernate {@link org.hibernate.Session}.
|
||||
* @param entityName the name of the persistent entity
|
||||
* @param entity the persistent instance to update
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#update(String, Object)
|
||||
*/
|
||||
void update(String entityName, Object entity) throws DataAccessException;
|
||||
@@ -406,7 +371,7 @@ public interface HibernateOperations {
|
||||
* @param entity the persistent instance to update
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#update(String, Object)
|
||||
*/
|
||||
void update(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
|
||||
@@ -440,7 +405,7 @@ public interface HibernateOperations {
|
||||
* @param entity the persistent object to replicate
|
||||
* @param replicationMode the Hibernate ReplicationMode
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode)
|
||||
* @see org.hibernate.Session#replicate(Object, ReplicationMode)
|
||||
*/
|
||||
void replicate(Object entity, ReplicationMode replicationMode) throws DataAccessException;
|
||||
|
||||
@@ -451,7 +416,7 @@ public interface HibernateOperations {
|
||||
* @param entity the persistent object to replicate
|
||||
* @param replicationMode the Hibernate ReplicationMode
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#replicate(String, Object, org.hibernate.ReplicationMode)
|
||||
* @see org.hibernate.Session#replicate(String, Object, ReplicationMode)
|
||||
*/
|
||||
void replicate(String entityName, Object entity, ReplicationMode replicationMode) throws DataAccessException;
|
||||
|
||||
@@ -460,7 +425,7 @@ public interface HibernateOperations {
|
||||
* <p>Similar to {@code save}, associating the given object
|
||||
* with the current Hibernate {@link org.hibernate.Session}.
|
||||
* @param entity the persistent instance to persist
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#persist(Object)
|
||||
* @see #save
|
||||
*/
|
||||
@@ -472,7 +437,7 @@ public interface HibernateOperations {
|
||||
* with the current Hibernate {@link org.hibernate.Session}.
|
||||
* @param entityName the name of the persistent entity
|
||||
* @param entity the persistent instance to persist
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#persist(String, Object)
|
||||
* @see #save
|
||||
*/
|
||||
@@ -491,10 +456,9 @@ public interface HibernateOperations {
|
||||
* object graph too.
|
||||
* @param entity the object to merge with the corresponding persistence instance
|
||||
* @return the updated, registered persistent instance
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#merge(Object)
|
||||
* @see #saveOrUpdate
|
||||
* @see org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener
|
||||
*/
|
||||
<T> T merge(T entity) throws DataAccessException;
|
||||
|
||||
@@ -512,7 +476,7 @@ public interface HibernateOperations {
|
||||
* @param entityName the name of the persistent entity
|
||||
* @param entity the object to merge with the corresponding persistence instance
|
||||
* @return the updated, registered persistent instance
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#merge(String, Object)
|
||||
* @see #saveOrUpdate
|
||||
*/
|
||||
@@ -521,7 +485,7 @@ public interface HibernateOperations {
|
||||
/**
|
||||
* Delete the given persistent instance.
|
||||
* @param entity the persistent instance to delete
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#delete(Object)
|
||||
*/
|
||||
void delete(Object entity) throws DataAccessException;
|
||||
@@ -533,7 +497,7 @@ public interface HibernateOperations {
|
||||
* @param entity the persistent instance to delete
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#delete(Object)
|
||||
*/
|
||||
void delete(Object entity, LockMode lockMode) throws DataAccessException;
|
||||
@@ -542,7 +506,7 @@ public interface HibernateOperations {
|
||||
* Delete the given persistent instance.
|
||||
* @param entityName the name of the persistent entity
|
||||
* @param entity the persistent instance to delete
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#delete(Object)
|
||||
*/
|
||||
void delete(String entityName, Object entity) throws DataAccessException;
|
||||
@@ -555,7 +519,7 @@ public interface HibernateOperations {
|
||||
* @param entity the persistent instance to delete
|
||||
* @param lockMode the lock mode to obtain
|
||||
* @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#delete(Object)
|
||||
*/
|
||||
void delete(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
|
||||
@@ -565,7 +529,7 @@ public interface HibernateOperations {
|
||||
* <p>This can be combined with any of the find methods to delete by query
|
||||
* in two lines of code.
|
||||
* @param entities the persistent instances to delete
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#delete(Object)
|
||||
*/
|
||||
void deleteAll(Collection<?> entities) throws DataAccessException;
|
||||
@@ -576,7 +540,7 @@ public interface HibernateOperations {
|
||||
* JDBC code needs to see certain changes within the same transaction.
|
||||
* Else, it is preferable to rely on auto-flushing at transaction
|
||||
* completion.
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#flush
|
||||
*/
|
||||
void flush() throws DataAccessException;
|
||||
@@ -584,7 +548,7 @@ public interface HibernateOperations {
|
||||
/**
|
||||
* Remove all objects from the {@link org.hibernate.Session} cache, and
|
||||
* cancel all pending saves, updates and deletes.
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#clear
|
||||
*/
|
||||
void clear() throws DataAccessException;
|
||||
@@ -594,33 +558,13 @@ public interface HibernateOperations {
|
||||
// Convenience finder methods for HQL strings
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute an HQL query.
|
||||
* @param queryString a query expressed in Hibernate's query language
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#createQuery
|
||||
*/
|
||||
List<?> find(String queryString) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute an HQL query, binding one value to a "?" parameter in the
|
||||
* query string.
|
||||
* @param queryString a query expressed in Hibernate's query language
|
||||
* @param value the value of the parameter
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#createQuery
|
||||
*/
|
||||
List<?> find(String queryString, Object value) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute an HQL query, binding a number of values to "?" parameters
|
||||
* in the query string.
|
||||
* @param queryString a query expressed in Hibernate's query language
|
||||
* @param values the values of the parameters
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#createQuery
|
||||
*/
|
||||
List<?> find(String queryString, Object... values) throws DataAccessException;
|
||||
@@ -632,7 +576,7 @@ public interface HibernateOperations {
|
||||
* @param paramName the name of the parameter
|
||||
* @param value the value of the parameter
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#getNamedQuery(String)
|
||||
*/
|
||||
List<?> findByNamedParam(String queryString, String paramName, Object value) throws DataAccessException;
|
||||
@@ -644,7 +588,7 @@ public interface HibernateOperations {
|
||||
* @param paramNames the names of the parameters
|
||||
* @param values the values of the parameters
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#getNamedQuery(String)
|
||||
*/
|
||||
List<?> findByNamedParam(String queryString, String[] paramNames, Object[] values) throws DataAccessException;
|
||||
@@ -655,7 +599,7 @@ public interface HibernateOperations {
|
||||
* @param queryString a query expressed in Hibernate's query language
|
||||
* @param valueBean the values of the parameters
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Query#setProperties
|
||||
* @see org.hibernate.Session#createQuery
|
||||
*/
|
||||
@@ -666,28 +610,6 @@ public interface HibernateOperations {
|
||||
// Convenience finder methods for named queries
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute a named query.
|
||||
* <p>A named query is defined in a Hibernate mapping file.
|
||||
* @param queryName the name of a Hibernate query in a mapping file
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#getNamedQuery(String)
|
||||
*/
|
||||
List<?> findByNamedQuery(String queryName) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a named query, binding one value to a "?" parameter in
|
||||
* the query string.
|
||||
* <p>A named query is defined in a Hibernate mapping file.
|
||||
* @param queryName the name of a Hibernate query in a mapping file
|
||||
* @param value the value of the parameter
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#getNamedQuery(String)
|
||||
*/
|
||||
List<?> findByNamedQuery(String queryName, Object value) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a named query binding a number of values to "?" parameters
|
||||
* in the query string.
|
||||
@@ -695,7 +617,7 @@ public interface HibernateOperations {
|
||||
* @param queryName the name of a Hibernate query in a mapping file
|
||||
* @param values the values of the parameters
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#getNamedQuery(String)
|
||||
*/
|
||||
List<?> findByNamedQuery(String queryName, Object... values) throws DataAccessException;
|
||||
@@ -708,7 +630,7 @@ public interface HibernateOperations {
|
||||
* @param paramName the name of parameter
|
||||
* @param value the value of the parameter
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#getNamedQuery(String)
|
||||
*/
|
||||
List<?> findByNamedQueryAndNamedParam(String queryName, String paramName, Object value)
|
||||
@@ -722,7 +644,7 @@ public interface HibernateOperations {
|
||||
* @param paramNames the names of the parameters
|
||||
* @param values the values of the parameters
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#getNamedQuery(String)
|
||||
*/
|
||||
List<?> findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values)
|
||||
@@ -735,7 +657,7 @@ public interface HibernateOperations {
|
||||
* @param queryName the name of a Hibernate query in a mapping file
|
||||
* @param valueBean the values of the parameters
|
||||
* @return a {@link List} containing the results of the query execution
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Query#setProperties
|
||||
* @see org.hibernate.Session#getNamedQuery(String)
|
||||
*/
|
||||
@@ -752,8 +674,8 @@ public interface HibernateOperations {
|
||||
* <b>Note: Do not reuse criteria objects! They need to recreated per execution,
|
||||
* due to the suboptimal design of Hibernate's criteria facility.</b>
|
||||
* @return a {@link List} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
|
||||
*/
|
||||
List<?> findByCriteria(DetachedCriteria criteria) throws DataAccessException;
|
||||
|
||||
@@ -767,8 +689,8 @@ public interface HibernateOperations {
|
||||
* @param maxResults the maximum number of result objects to retrieve
|
||||
* (or <=0 for no limit)
|
||||
* @return a {@link List} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
|
||||
* @see org.hibernate.Criteria#setFirstResult(int)
|
||||
* @see org.hibernate.Criteria#setMaxResults(int)
|
||||
*/
|
||||
@@ -779,7 +701,7 @@ public interface HibernateOperations {
|
||||
* @param exampleEntity an instance of the desired entity,
|
||||
* serving as example for "query-by-example"
|
||||
* @return a {@link List} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.criterion.Example#create(Object)
|
||||
*/
|
||||
<T> List<T> findByExample(T exampleEntity) throws DataAccessException;
|
||||
@@ -790,7 +712,7 @@ public interface HibernateOperations {
|
||||
* @param exampleEntity an instance of the desired entity,
|
||||
* serving as example for "query-by-example"
|
||||
* @return a {@link List} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.criterion.Example#create(Object)
|
||||
*/
|
||||
<T> List<T> findByExample(String entityName, T exampleEntity) throws DataAccessException;
|
||||
@@ -804,7 +726,7 @@ public interface HibernateOperations {
|
||||
* @param maxResults the maximum number of result objects to retrieve
|
||||
* (or <=0 for no limit)
|
||||
* @return a {@link List} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.criterion.Example#create(Object)
|
||||
* @see org.hibernate.Criteria#setFirstResult(int)
|
||||
* @see org.hibernate.Criteria#setMaxResults(int)
|
||||
@@ -821,7 +743,7 @@ public interface HibernateOperations {
|
||||
* @param maxResults the maximum number of result objects to retrieve
|
||||
* (or <=0 for no limit)
|
||||
* @return a {@link List} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.criterion.Example#create(Object)
|
||||
* @see org.hibernate.Criteria#setFirstResult(int)
|
||||
* @see org.hibernate.Criteria#setMaxResults(int)
|
||||
@@ -834,32 +756,6 @@ public interface HibernateOperations {
|
||||
// Convenience query methods for iteration and bulk updates/deletes
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute a query for persistent instances.
|
||||
* <p>Returns the results as an {@link Iterator}. Entities returned are
|
||||
* initialized on demand. See the Hibernate API documentation for details.
|
||||
* @param queryString a query expressed in Hibernate's query language
|
||||
* @return an {@link Iterator} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#createQuery
|
||||
* @see org.hibernate.Query#iterate
|
||||
*/
|
||||
Iterator<?> iterate(String queryString) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for persistent instances, binding one value
|
||||
* to a "?" parameter in the query string.
|
||||
* <p>Returns the results as an {@link Iterator}. Entities returned are
|
||||
* initialized on demand. See the Hibernate API documentation for details.
|
||||
* @param queryString a query expressed in Hibernate's query language
|
||||
* @param value the value of the parameter
|
||||
* @return an {@link Iterator} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#createQuery
|
||||
* @see org.hibernate.Query#iterate
|
||||
*/
|
||||
Iterator<?> iterate(String queryString, Object value) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for persistent instances, binding a number of
|
||||
* values to "?" parameters in the query string.
|
||||
@@ -868,7 +764,7 @@ public interface HibernateOperations {
|
||||
* @param queryString a query expressed in Hibernate's query language
|
||||
* @param values the values of the parameters
|
||||
* @return an {@link Iterator} containing 0 or more persistent instances
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#createQuery
|
||||
* @see org.hibernate.Query#iterate
|
||||
*/
|
||||
@@ -884,35 +780,13 @@ public interface HibernateOperations {
|
||||
*/
|
||||
void closeIterator(Iterator<?> it) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Update/delete all objects according to the given query.
|
||||
* @param queryString an update/delete query expressed in Hibernate's query language
|
||||
* @return the number of instances updated/deleted
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#createQuery
|
||||
* @see org.hibernate.Query#executeUpdate
|
||||
*/
|
||||
int bulkUpdate(String queryString) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Update/delete all objects according to the given query, binding one value
|
||||
* to a "?" parameter in the query string.
|
||||
* @param queryString an update/delete query expressed in Hibernate's query language
|
||||
* @param value the value of the parameter
|
||||
* @return the number of instances updated/deleted
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#createQuery
|
||||
* @see org.hibernate.Query#executeUpdate
|
||||
*/
|
||||
int bulkUpdate(String queryString, Object value) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Update/delete all objects according to the given query, binding a number of
|
||||
* values to "?" parameters in the query string.
|
||||
* @param queryString an update/delete query expressed in Hibernate's query language
|
||||
* @param values the values of the parameters
|
||||
* @return the number of instances updated/deleted
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
* @see org.hibernate.Session#createQuery
|
||||
* @see org.hibernate.Query#executeUpdate
|
||||
*/
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -14,25 +14,23 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import org.hibernate.OptimisticLockException;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.dialect.lock.OptimisticEntityLockException;
|
||||
|
||||
import org.springframework.orm.ObjectOptimisticLockingFailureException;
|
||||
|
||||
/**
|
||||
* Hibernate-specific subclass of ObjectOptimisticLockingFailureException.
|
||||
* Converts Hibernate's StaleObjectStateException, StaleStateException
|
||||
* and OptimisticLockException.
|
||||
* and OptimisticEntityLockException.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @since 4.2
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
|
||||
|
||||
@@ -44,7 +42,7 @@ public class HibernateOptimisticLockingFailureException extends ObjectOptimistic
|
||||
super(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
public HibernateOptimisticLockingFailureException(OptimisticLockException ex) {
|
||||
public HibernateOptimisticLockingFailureException(OptimisticEntityLockException ex) {
|
||||
super(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import org.hibernate.QueryException;
|
||||
|
||||
@@ -25,11 +25,9 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
* thrown on invalid HQL query syntax.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @since 4.2
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateQueryException extends InvalidDataAccessResourceUsageException {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
||||
@@ -26,11 +26,9 @@ import org.springframework.dao.UncategorizedDataAccessException;
|
||||
* {@code org.springframework.dao} exceptions.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @since 4.2
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateSystemException extends UncategorizedDataAccessException {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -14,36 +14,36 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.Filter;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.ReplicationMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.criterion.DetachedCriteria;
|
||||
import org.hibernate.criterion.Example;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.event.EventSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -64,54 +64,30 @@ import org.springframework.util.Assert;
|
||||
* always be configured as bean in the application context, in the first case
|
||||
* given to the service directly, in the second case to the prepared template.
|
||||
*
|
||||
* <p><b>NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
|
||||
* also be coded in plain Hibernate style. Hence, for newly started projects,
|
||||
* consider adopting the standard Hibernate3 style of coding data access objects
|
||||
* instead, based on {@link org.hibernate.SessionFactory#getCurrentSession()}.</b>
|
||||
*
|
||||
* <p>This class can be considered as direct alternative to working with the raw
|
||||
* Hibernate3 Session API (through {@code SessionFactory.getCurrentSession()}).
|
||||
* The major advantage is its automatic conversion to DataAccessExceptions as well
|
||||
* as its capability to fall back to 'auto-commit' style behavior when used outside
|
||||
* of transactions. <b>Note that HibernateTemplate will perform its own Session
|
||||
* management, not participating in a custom Hibernate CurrentSessionContext
|
||||
* unless you explicitly switch {@link #setAllowCreate "allowCreate"} to "false".</b>
|
||||
*
|
||||
* <p>{@link LocalSessionFactoryBean} is the preferred way of obtaining a reference
|
||||
* to a specific Hibernate SessionFactory, at least in a non-EJB environment.
|
||||
* The Spring application context will manage its lifecycle, initializing and
|
||||
* shutting down the factory as part of the application.
|
||||
*
|
||||
* <p>Note that operations that return an Iterator (i.e. {@code iterate})
|
||||
* are supposed to be used within Spring-driven or JTA-driven transactions
|
||||
* (with HibernateTransactionManager, JtaTransactionManager, or EJB CMT).
|
||||
* Else, the Iterator won't be able to read results from its ResultSet anymore,
|
||||
* as the underlying Hibernate Session will already have been closed.
|
||||
*
|
||||
* <p>Lazy loading will also just work with an open Hibernate Session,
|
||||
* either within a transaction or within OpenSessionInViewFilter/Interceptor.
|
||||
* Furthermore, some operations just make sense within transactions,
|
||||
* for example: {@code contains}, {@code evict}, {@code lock},
|
||||
* {@code flush}, {@code clear}.
|
||||
* <p><b>NOTE: Hibernate access code can also be coded in plain Hibernate style.
|
||||
* Hence, for newly started projects, consider adopting the standard Hibernate
|
||||
* style of coding data access objects instead, based on
|
||||
* {@link SessionFactory#getCurrentSession()}.
|
||||
* This HibernateTemplate primarily exists as a migration helper for Hibernate 3
|
||||
* based data access code, to benefit from bug fixes in Hibernate 5.x.</b>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @since 4.2
|
||||
* @see #setSessionFactory
|
||||
* @see HibernateCallback
|
||||
* @see org.hibernate.Session
|
||||
* @see Session
|
||||
* @see LocalSessionFactoryBean
|
||||
* @see HibernateTransactionManager
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
|
||||
* @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
* @see org.springframework.orm.hibernate5.support.OpenSessionInViewFilter
|
||||
* @see org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor
|
||||
*/
|
||||
@Deprecated
|
||||
public class HibernateTemplate extends HibernateAccessor implements HibernateOperations {
|
||||
public class HibernateTemplate implements HibernateOperations, InitializingBean {
|
||||
|
||||
private boolean allowCreate = true;
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private boolean alwaysUseNewSession = false;
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private String[] filterNames;
|
||||
|
||||
private boolean exposeNativeSession = false;
|
||||
|
||||
@@ -141,72 +117,42 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
afterPropertiesSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new HibernateTemplate instance.
|
||||
* @param sessionFactory the SessionFactory to create Sessions with
|
||||
* @param allowCreate if a non-transactional Session should be created when no
|
||||
* transactional Session can be found for the current thread
|
||||
*/
|
||||
public HibernateTemplate(SessionFactory sessionFactory, boolean allowCreate) {
|
||||
setSessionFactory(sessionFactory);
|
||||
setAllowCreate(allowCreate);
|
||||
afterPropertiesSet();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set if a new {@link Session} should be created when no transactional
|
||||
* {@code Session} can be found for the current thread.
|
||||
* The default value is {@code true}.
|
||||
* <p>{@code HibernateTemplate} is aware of a corresponding
|
||||
* {@code Session} bound to the current thread, for example when using
|
||||
* {@link HibernateTransactionManager}. If {@code allowCreate} is
|
||||
* {@code true}, a new non-transactional {@code Session} will be
|
||||
* created if none is found, which needs to be closed at the end of the operation.
|
||||
* If {@code false}, an {@link IllegalStateException} will get thrown in
|
||||
* this case.
|
||||
* <p><b>NOTE: As of Spring 2.5, switching {@code allowCreate}
|
||||
* to {@code false} will delegate to Hibernate's
|
||||
* {@link org.hibernate.SessionFactory#getCurrentSession()} method,</b>
|
||||
* which - with Spring-based setup - will by default delegate to Spring's
|
||||
* {@code SessionFactoryUtils.getSession(sessionFactory, false)}.
|
||||
* This mode also allows for custom Hibernate CurrentSessionContext strategies
|
||||
* to be plugged in, whereas {@code allowCreate} set to {@code true}
|
||||
* will always use a Spring-managed Hibernate Session.
|
||||
* @see SessionFactoryUtils#getSession(SessionFactory, boolean)
|
||||
* Set the Hibernate SessionFactory that should be used to create
|
||||
* Hibernate Sessions.
|
||||
*/
|
||||
public void setAllowCreate(boolean allowCreate) {
|
||||
this.allowCreate = allowCreate;
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if a new Session should be created if no thread-bound found.
|
||||
* Return the Hibernate SessionFactory that should be used to create
|
||||
* Hibernate Sessions.
|
||||
*/
|
||||
public boolean isAllowCreate() {
|
||||
return this.allowCreate;
|
||||
public SessionFactory getSessionFactory() {
|
||||
return this.sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to always use a new Hibernate Session for this template.
|
||||
* Default is "false"; if activated, all operations on this template will
|
||||
* work on a new Hibernate Session even in case of a pre-bound Session
|
||||
* (for example, within a transaction or OpenSessionInViewFilter).
|
||||
* <p>Within a transaction, a new Hibernate Session used by this template
|
||||
* will participate in the transaction through using the same JDBC
|
||||
* Connection. In such a scenario, multiple Sessions will participate
|
||||
* in the same database transaction.
|
||||
* <p>Turn this on for operations that are supposed to always execute
|
||||
* independently, without side effects caused by a shared Hibernate Session.
|
||||
* Set one or more names of Hibernate filters to be activated for all
|
||||
* Sessions that this accessor works with.
|
||||
* <p>Each of those filters will be enabled at the beginning of each
|
||||
* operation and correspondingly disabled at the end of the operation.
|
||||
* This will work for newly opened Sessions as well as for existing
|
||||
* Sessions (for example, within a transaction).
|
||||
* @see #enableFilters(Session)
|
||||
* @see Session#enableFilter(String)
|
||||
*/
|
||||
public void setAlwaysUseNewSession(boolean alwaysUseNewSession) {
|
||||
this.alwaysUseNewSession = alwaysUseNewSession;
|
||||
public void setFilterNames(String... filterNames) {
|
||||
this.filterNames = filterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to always use a new Hibernate Session for this template.
|
||||
* Return the names of Hibernate filters to be activated, if any.
|
||||
*/
|
||||
public boolean isAlwaysUseNewSession() {
|
||||
return this.alwaysUseNewSession;
|
||||
public String[] getFilterNames() {
|
||||
return this.filterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +162,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
* {@code close} calls and automatically applying query cache
|
||||
* settings and transaction timeouts.
|
||||
* @see HibernateCallback
|
||||
* @see org.hibernate.Session
|
||||
* @see Session
|
||||
* @see #setCacheQueries
|
||||
* @see #setQueryCacheRegion
|
||||
* @see #prepareQuery
|
||||
@@ -239,8 +185,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
* in case of write operations (save/update/delete).
|
||||
* <p>Default is "true", for fail-fast behavior when attempting write operations
|
||||
* within a read-only transaction. Turn this off to allow save/update/delete
|
||||
* on a Session with flush mode NEVER.
|
||||
* @see #setFlushMode
|
||||
* on a Session with flush mode MANUAL.
|
||||
* @see #checkWriteOperationAllowed
|
||||
* @see org.springframework.transaction.TransactionDefinition#isReadOnly
|
||||
*/
|
||||
@@ -265,7 +210,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
* by this template, set the "queryCacheRegion" property.
|
||||
* @see #setQueryCacheRegion
|
||||
* @see org.hibernate.Query#setCacheable
|
||||
* @see org.hibernate.Criteria#setCacheable
|
||||
* @see Criteria#setCacheable
|
||||
*/
|
||||
public void setCacheQueries(boolean cacheQueries) {
|
||||
this.cacheQueries = cacheQueries;
|
||||
@@ -286,7 +231,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
* template are configured to be cached via the "cacheQueries" property.
|
||||
* @see #setCacheQueries
|
||||
* @see org.hibernate.Query#setCacheRegion
|
||||
* @see org.hibernate.Criteria#setCacheRegion
|
||||
* @see Criteria#setCacheRegion
|
||||
*/
|
||||
public void setQueryCacheRegion(String queryCacheRegion) {
|
||||
this.queryCacheRegion = queryCacheRegion;
|
||||
@@ -336,141 +281,77 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
return this.maxResults;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (getSessionFactory() == null) {
|
||||
throw new IllegalArgumentException("Property 'sessionFactory' is required");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T execute(HibernateCallback<T> action) throws DataAccessException {
|
||||
return doExecute(action, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public List<?> executeFind(HibernateCallback<?> action) throws DataAccessException {
|
||||
Object result = doExecute(action, false, false);
|
||||
if (result != null && !(result instanceof List)) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Result object returned from HibernateCallback isn't a List: [" + result + "]");
|
||||
}
|
||||
return (List<?>) result;
|
||||
return doExecute(action, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the action specified by the given action object within a
|
||||
* new {@link org.hibernate.Session}.
|
||||
* <p>This execute variant overrides the template-wide
|
||||
* {@link #isAlwaysUseNewSession() "alwaysUseNewSession"} setting.
|
||||
* @param action callback object that specifies the Hibernate action
|
||||
* @return a result object returned by the action, or {@code null}
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
*/
|
||||
public <T> T executeWithNewSession(HibernateCallback<T> action) {
|
||||
return doExecute(action, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the action specified by the given action object within a
|
||||
* native {@link org.hibernate.Session}.
|
||||
* native {@link Session}.
|
||||
* <p>This execute variant overrides the template-wide
|
||||
* {@link #isExposeNativeSession() "exposeNativeSession"} setting.
|
||||
* @param action callback object that specifies the Hibernate action
|
||||
* @return a result object returned by the action, or {@code null}
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
*/
|
||||
public <T> T executeWithNativeSession(HibernateCallback<T> action) {
|
||||
return doExecute(action, false, true);
|
||||
return doExecute(action, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the action specified by the given action object within a Session.
|
||||
* @param action callback object that specifies the Hibernate action
|
||||
* @param enforceNewSession whether to enforce a new Session for this template
|
||||
* even if there is a pre-bound transactional Session
|
||||
* @param enforceNativeSession whether to enforce exposure of the native
|
||||
* Hibernate Session to callback code
|
||||
* @return a result object returned by the action, or {@code null}
|
||||
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
|
||||
* @throws DataAccessException in case of Hibernate errors
|
||||
*/
|
||||
protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNewSession, boolean enforceNativeSession)
|
||||
throws DataAccessException {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNativeSession) throws DataAccessException {
|
||||
Assert.notNull(action, "Callback object must not be null");
|
||||
|
||||
Session session = (enforceNewSession ?
|
||||
SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
|
||||
boolean existingTransaction = (!enforceNewSession &&
|
||||
(!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
|
||||
if (existingTransaction) {
|
||||
logger.debug("Found thread-bound Session for HibernateTemplate");
|
||||
Session session = null;
|
||||
boolean isNew = false;
|
||||
try {
|
||||
session = getSessionFactory().getCurrentSession();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
logger.debug("Could not retrieve pre-bound Hibernate session", ex);
|
||||
}
|
||||
if (session == null) {
|
||||
session = getSessionFactory().openSession();
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
FlushMode previousFlushMode = null;
|
||||
try {
|
||||
previousFlushMode = applyFlushMode(session, existingTransaction);
|
||||
enableFilters(session);
|
||||
Session sessionToExpose =
|
||||
(enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
|
||||
T result = action.doInHibernate(sessionToExpose);
|
||||
flushIfNecessary(session, existingTransaction);
|
||||
return result;
|
||||
return action.doInHibernate(sessionToExpose);
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw convertHibernateAccessException(ex);
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
throw convertJdbcAccessException(ex);
|
||||
throw SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
// Callback code threw application exception...
|
||||
throw ex;
|
||||
}
|
||||
finally {
|
||||
if (existingTransaction) {
|
||||
logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
|
||||
disableFilters(session);
|
||||
if (previousFlushMode != null) {
|
||||
session.setFlushMode(previousFlushMode);
|
||||
}
|
||||
if (isNew) {
|
||||
SessionFactoryUtils.closeSession(session);
|
||||
}
|
||||
else {
|
||||
// Never use deferred close for an explicitly new Session.
|
||||
if (isAlwaysUseNewSession()) {
|
||||
SessionFactoryUtils.closeSession(session);
|
||||
}
|
||||
else {
|
||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Session for use by this template.
|
||||
* <p>Returns a new Session in case of "alwaysUseNewSession" (using the same
|
||||
* JDBC Connection as a transactional Session, if applicable), a pre-bound
|
||||
* Session in case of "allowCreate" turned off, and a pre-bound or new Session
|
||||
* otherwise (new only if no transactional or otherwise pre-bound Session exists).
|
||||
* @return the Session to use (never {@code null})
|
||||
* @see SessionFactoryUtils#getSession
|
||||
* @see SessionFactoryUtils#getNewSession
|
||||
* @see #setAlwaysUseNewSession
|
||||
* @see #setAllowCreate
|
||||
*/
|
||||
protected Session getSession() {
|
||||
if (isAlwaysUseNewSession()) {
|
||||
return SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor());
|
||||
}
|
||||
else if (isAllowCreate()) {
|
||||
return SessionFactoryUtils.getSession(
|
||||
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
|
||||
}
|
||||
else if (SessionFactoryUtils.hasTransactionalSession(getSessionFactory())) {
|
||||
return SessionFactoryUtils.getSession(getSessionFactory(), false);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return getSessionFactory().getCurrentSession();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not obtain current Hibernate Session", ex);
|
||||
disableFilters(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,28 +361,46 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
* The proxy also prepares returned Query and Criteria objects.
|
||||
* @param session the Hibernate Session to create a proxy for
|
||||
* @return the Session proxy
|
||||
* @see org.hibernate.Session#close()
|
||||
* @see Session#close()
|
||||
* @see #prepareQuery
|
||||
* @see #prepareCriteria
|
||||
*/
|
||||
protected Session createSessionProxy(Session session) {
|
||||
Class<?>[] sessionIfcs;
|
||||
Class<?> mainIfc = (session instanceof org.hibernate.classic.Session ?
|
||||
org.hibernate.classic.Session.class : Session.class);
|
||||
if (session instanceof EventSource) {
|
||||
sessionIfcs = new Class<?>[] {mainIfc, EventSource.class};
|
||||
}
|
||||
else if (session instanceof SessionImplementor) {
|
||||
sessionIfcs = new Class<?>[] {mainIfc, SessionImplementor.class};
|
||||
}
|
||||
else {
|
||||
sessionIfcs = new Class<?>[] {mainIfc};
|
||||
}
|
||||
return (Session) Proxy.newProxyInstance(
|
||||
session.getClass().getClassLoader(), sessionIfcs,
|
||||
session.getClass().getClassLoader(), new Class<?>[] {Session.class},
|
||||
new CloseSuppressingInvocationHandler(session));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the specified filters on the given Session.
|
||||
* @param session the current Hibernate Session
|
||||
* @see #setFilterNames
|
||||
* @see Session#enableFilter(String)
|
||||
*/
|
||||
protected void enableFilters(Session session) {
|
||||
String[] filterNames = getFilterNames();
|
||||
if (filterNames != null) {
|
||||
for (String filterName : filterNames) {
|
||||
session.enableFilter(filterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the specified filters on the given Session.
|
||||
* @param session the current Hibernate Session
|
||||
* @see #setFilterNames
|
||||
* @see Session#disableFilter(String)
|
||||
*/
|
||||
protected void disableFilters(Session session) {
|
||||
String[] filterNames = getFilterNames();
|
||||
if (filterNames != null) {
|
||||
for (String filterName : filterNames) {
|
||||
session.disableFilter(filterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Convenience methods for loading individual objects
|
||||
@@ -518,13 +417,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
|
||||
return executeWithNativeSession(new HibernateCallback<T>() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T doInHibernate(Session session) throws HibernateException {
|
||||
if (lockMode != null) {
|
||||
return (T) session.get(entityClass, id, lockMode);
|
||||
return session.get(entityClass, id, new LockOptions(lockMode));
|
||||
}
|
||||
else {
|
||||
return (T) session.get(entityClass, id);
|
||||
return session.get(entityClass, id);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -543,7 +441,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
@Override
|
||||
public Object doInHibernate(Session session) throws HibernateException {
|
||||
if (lockMode != null) {
|
||||
return session.get(entityName, id, lockMode);
|
||||
return session.get(entityName, id, new LockOptions(lockMode));
|
||||
}
|
||||
else {
|
||||
return session.get(entityName, id);
|
||||
@@ -563,13 +461,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
|
||||
return executeWithNativeSession(new HibernateCallback<T>() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T doInHibernate(Session session) throws HibernateException {
|
||||
if (lockMode != null) {
|
||||
return (T) session.load(entityClass, id, lockMode);
|
||||
return session.load(entityClass, id, new LockOptions(lockMode));
|
||||
}
|
||||
else {
|
||||
return (T) session.load(entityClass, id);
|
||||
return session.load(entityClass, id);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -588,7 +485,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
@Override
|
||||
public Object doInHibernate(Session session) throws HibernateException {
|
||||
if (lockMode != null) {
|
||||
return session.load(entityName, id, lockMode);
|
||||
return session.load(entityName, id, new LockOptions(lockMode));
|
||||
}
|
||||
else {
|
||||
return session.load(entityName, id);
|
||||
@@ -601,7 +498,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
public <T> List<T> loadAll(final Class<T> entityClass) throws DataAccessException {
|
||||
return executeWithNativeSession(new HibernateCallback<List<T>>() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({"unchecked", "deprecation"})
|
||||
public List<T> doInHibernate(Session session) throws HibernateException {
|
||||
Criteria criteria = session.createCriteria(entityClass);
|
||||
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
|
||||
@@ -633,7 +530,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
@Override
|
||||
public Object doInHibernate(Session session) throws HibernateException {
|
||||
if (lockMode != null) {
|
||||
session.refresh(entity, lockMode);
|
||||
session.refresh(entity, new LockOptions(lockMode));
|
||||
}
|
||||
else {
|
||||
session.refresh(entity);
|
||||
@@ -676,7 +573,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
|
||||
@Override
|
||||
public Filter enableFilter(String filterName) throws IllegalStateException {
|
||||
Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
|
||||
Session session = getSessionFactory().getCurrentSession();
|
||||
Filter filter = session.getEnabledFilter(filterName);
|
||||
if (filter == null) {
|
||||
filter = session.enableFilter(filterName);
|
||||
@@ -694,7 +591,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
executeWithNativeSession(new HibernateCallback<Object>() {
|
||||
@Override
|
||||
public Object doInHibernate(Session session) throws HibernateException {
|
||||
session.lock(entity, lockMode);
|
||||
session.buildLockRequest(new LockOptions(lockMode)).lock(entity);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -707,7 +604,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
executeWithNativeSession(new HibernateCallback<Object>() {
|
||||
@Override
|
||||
public Object doInHibernate(Session session) throws HibernateException {
|
||||
session.lock(entityName, entity, lockMode);
|
||||
session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -748,7 +645,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
checkWriteOperationAllowed(session);
|
||||
session.update(entity);
|
||||
if (lockMode != null) {
|
||||
session.lock(entity, lockMode);
|
||||
session.buildLockRequest(new LockOptions(lockMode)).lock(entity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -770,7 +667,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
checkWriteOperationAllowed(session);
|
||||
session.update(entityName, entity);
|
||||
if (lockMode != null) {
|
||||
session.lock(entity, lockMode);
|
||||
session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -889,7 +786,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
public Object doInHibernate(Session session) throws HibernateException {
|
||||
checkWriteOperationAllowed(session);
|
||||
if (lockMode != null) {
|
||||
session.lock(entity, lockMode);
|
||||
session.buildLockRequest(new LockOptions(lockMode)).lock(entity);
|
||||
}
|
||||
session.delete(entity);
|
||||
return null;
|
||||
@@ -911,7 +808,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
public Object doInHibernate(Session session) throws HibernateException {
|
||||
checkWriteOperationAllowed(session);
|
||||
if (lockMode != null) {
|
||||
session.lock(entityName, entity, lockMode);
|
||||
session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity);
|
||||
}
|
||||
session.delete(entityName, entity);
|
||||
return null;
|
||||
@@ -960,22 +857,13 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
// Convenience finder methods for HQL strings
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public List<?> find(String queryString) throws DataAccessException {
|
||||
return find(queryString, (Object[]) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> find(String queryString, Object value) throws DataAccessException {
|
||||
return find(queryString, new Object[] {value});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> find(final String queryString, final Object... values) throws DataAccessException {
|
||||
return executeWithNativeSession(new HibernateCallback<List<?>>() {
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
public List<?> doInHibernate(Session session) throws HibernateException {
|
||||
Query queryObject = session.createQuery(queryString);
|
||||
org.hibernate.Query queryObject = session.createQuery(queryString);
|
||||
prepareQuery(queryObject);
|
||||
if (values != null) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
@@ -1003,13 +891,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
}
|
||||
return executeWithNativeSession(new HibernateCallback<List<?>>() {
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
public List<?> doInHibernate(Session session) throws HibernateException {
|
||||
Query queryObject = session.createQuery(queryString);
|
||||
org.hibernate.Query queryObject = session.createQuery(queryString);
|
||||
prepareQuery(queryObject);
|
||||
if (values != null) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
|
||||
}
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
|
||||
}
|
||||
return queryObject.list();
|
||||
}
|
||||
@@ -1022,8 +909,9 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
|
||||
return executeWithNativeSession(new HibernateCallback<List<?>>() {
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
public List<?> doInHibernate(Session session) throws HibernateException {
|
||||
Query queryObject = session.createQuery(queryString);
|
||||
org.hibernate.Query queryObject = session.createQuery(queryString);
|
||||
prepareQuery(queryObject);
|
||||
queryObject.setProperties(valueBean);
|
||||
return queryObject.list();
|
||||
@@ -1036,22 +924,13 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
// Convenience finder methods for named queries
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public List<?> findByNamedQuery(String queryName) throws DataAccessException {
|
||||
return findByNamedQuery(queryName, (Object[]) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> findByNamedQuery(String queryName, Object value) throws DataAccessException {
|
||||
return findByNamedQuery(queryName, new Object[] {value});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> findByNamedQuery(final String queryName, final Object... values) throws DataAccessException {
|
||||
return executeWithNativeSession(new HibernateCallback<List<?>>() {
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
public List<?> doInHibernate(Session session) throws HibernateException {
|
||||
Query queryObject = session.getNamedQuery(queryName);
|
||||
org.hibernate.Query queryObject = session.getNamedQuery(queryName);
|
||||
prepareQuery(queryObject);
|
||||
if (values != null) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
@@ -1080,8 +959,9 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
}
|
||||
return executeWithNativeSession(new HibernateCallback<List<?>>() {
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
public List<?> doInHibernate(Session session) throws HibernateException {
|
||||
Query queryObject = session.getNamedQuery(queryName);
|
||||
org.hibernate.Query queryObject = session.getNamedQuery(queryName);
|
||||
prepareQuery(queryObject);
|
||||
if (values != null) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
@@ -1099,8 +979,9 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
|
||||
return executeWithNativeSession(new HibernateCallback<List<?>>() {
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
public List<?> doInHibernate(Session session) throws HibernateException {
|
||||
Query queryObject = session.getNamedQuery(queryName);
|
||||
org.hibernate.Query queryObject = session.getNamedQuery(queryName);
|
||||
prepareQuery(queryObject);
|
||||
queryObject.setProperties(valueBean);
|
||||
return queryObject.list();
|
||||
@@ -1155,6 +1036,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public <T> List<T> findByExample(
|
||||
final String entityName, final T exampleEntity, final int firstResult, final int maxResults)
|
||||
throws DataAccessException {
|
||||
@@ -1184,22 +1066,13 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
// Convenience query methods for iteration and bulk updates/deletes
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public Iterator<?> iterate(String queryString) throws DataAccessException {
|
||||
return iterate(queryString, (Object[]) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<?> iterate(String queryString, Object value) throws DataAccessException {
|
||||
return iterate(queryString, new Object[] {value});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<?> iterate(final String queryString, final Object... values) throws DataAccessException {
|
||||
return executeWithNativeSession(new HibernateCallback<Iterator<?>>() {
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
public Iterator<?> doInHibernate(Session session) throws HibernateException {
|
||||
Query queryObject = session.createQuery(queryString);
|
||||
org.hibernate.Query queryObject = session.createQuery(queryString);
|
||||
prepareQuery(queryObject);
|
||||
if (values != null) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
@@ -1221,22 +1094,13 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bulkUpdate(String queryString) throws DataAccessException {
|
||||
return bulkUpdate(queryString, (Object[]) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bulkUpdate(String queryString, Object value) throws DataAccessException {
|
||||
return bulkUpdate(queryString, new Object[] {value});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bulkUpdate(final String queryString, final Object... values) throws DataAccessException {
|
||||
return executeWithNativeSession(new HibernateCallback<Integer>() {
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
public Integer doInHibernate(Session session) throws HibernateException {
|
||||
Query queryObject = session.createQuery(queryString);
|
||||
org.hibernate.Query queryObject = session.createQuery(queryString);
|
||||
prepareQuery(queryObject);
|
||||
if (values != null) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
@@ -1260,14 +1124,11 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
* @param session current Hibernate Session
|
||||
* @throws InvalidDataAccessApiUsageException if write operations are not allowed
|
||||
* @see #setCheckWriteOperations
|
||||
* @see #getFlushMode()
|
||||
* @see #FLUSH_EAGER
|
||||
* @see org.hibernate.Session#getFlushMode()
|
||||
* @see org.hibernate.FlushMode#MANUAL
|
||||
* @see Session#getFlushMode()
|
||||
* @see FlushMode#MANUAL
|
||||
*/
|
||||
protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
|
||||
if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&
|
||||
session.getFlushMode().lessThan(FlushMode.COMMIT)) {
|
||||
if (isCheckWriteOperations() && SessionFactoryUtils.getFlushMode(session).lessThan(FlushMode.COMMIT)) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Write operations are not allowed in read-only mode (FlushMode.MANUAL): "+
|
||||
"Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.");
|
||||
@@ -1280,9 +1141,9 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
* @param queryObject the Query object to prepare
|
||||
* @see #setCacheQueries
|
||||
* @see #setQueryCacheRegion
|
||||
* @see SessionFactoryUtils#applyTransactionTimeout
|
||||
*/
|
||||
protected void prepareQuery(Query queryObject) {
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
protected void prepareQuery(org.hibernate.Query queryObject) {
|
||||
if (isCacheQueries()) {
|
||||
queryObject.setCacheable(true);
|
||||
if (getQueryCacheRegion() != null) {
|
||||
@@ -1295,7 +1156,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
if (getMaxResults() > 0) {
|
||||
queryObject.setMaxResults(getMaxResults());
|
||||
}
|
||||
SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
|
||||
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
||||
if (sessionHolder != null && sessionHolder.hasTimeout()) {
|
||||
queryObject.setTimeout(sessionHolder.getTimeToLiveInSeconds());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1304,7 +1170,6 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
* @param criteria the Criteria object to prepare
|
||||
* @see #setCacheQueries
|
||||
* @see #setQueryCacheRegion
|
||||
* @see SessionFactoryUtils#applyTransactionTimeout
|
||||
*/
|
||||
protected void prepareCriteria(Criteria criteria) {
|
||||
if (isCacheQueries()) {
|
||||
@@ -1319,7 +1184,12 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
if (getMaxResults() > 0) {
|
||||
criteria.setMaxResults(getMaxResults());
|
||||
}
|
||||
SessionFactoryUtils.applyTransactionTimeout(criteria, getSessionFactory());
|
||||
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
||||
if (sessionHolder != null && sessionHolder.hasTimeout()) {
|
||||
criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1329,7 +1199,8 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
* @param value the value of the parameter
|
||||
* @throws HibernateException if thrown by the Query object
|
||||
*/
|
||||
protected void applyNamedParameterToQuery(Query queryObject, String paramName, Object value)
|
||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
||||
protected void applyNamedParameterToQuery(org.hibernate.Query queryObject, String paramName, Object value)
|
||||
throws HibernateException {
|
||||
|
||||
if (value instanceof Collection) {
|
||||
@@ -1347,7 +1218,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
/**
|
||||
* Invocation handler that suppresses close calls on Hibernate Sessions.
|
||||
* Also prepares returned Query and Criteria objects.
|
||||
* @see org.hibernate.Session#close
|
||||
* @see Session#close
|
||||
*/
|
||||
private class CloseSuppressingInvocationHandler implements InvocationHandler {
|
||||
|
||||
@@ -1358,6 +1229,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
// Invocation on Session interface coming in...
|
||||
|
||||
@@ -1380,8 +1252,8 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe
|
||||
|
||||
// If return value is a Query or Criteria, apply transaction timeout.
|
||||
// Applies to createQuery, getNamedQuery, createCriteria.
|
||||
if (retVal instanceof Query) {
|
||||
prepareQuery(((Query) retVal));
|
||||
if (retVal instanceof org.hibernate.Query) {
|
||||
prepareQuery(((org.hibernate.Query) retVal));
|
||||
}
|
||||
if (retVal instanceof Criteria) {
|
||||
prepareCriteria(((Criteria) retVal));
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -14,21 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3;
|
||||
package org.springframework.orm.hibernate5;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.exception.GenericJDBCException;
|
||||
import org.hibernate.impl.SessionImpl;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.resource.transaction.spi.TransactionStatus;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -40,8 +40,6 @@ import org.springframework.jdbc.datasource.ConnectionHolder;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
|
||||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
|
||||
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
|
||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
||||
import org.springframework.transaction.CannotCreateTransactionException;
|
||||
import org.springframework.transaction.IllegalTransactionStateException;
|
||||
import org.springframework.transaction.InvalidIsolationLevelException;
|
||||
@@ -54,13 +52,12 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
|
||||
/**
|
||||
* {@link org.springframework.transaction.PlatformTransactionManager}
|
||||
* implementation for a single Hibernate {@link org.hibernate.SessionFactory}.
|
||||
* Binds a Hibernate Session from the specified factory to the thread, potentially
|
||||
* allowing for one thread-bound Session per factory. {@link SessionFactoryUtils}
|
||||
* and {@link HibernateTemplate} are aware of thread-bound Sessions and participate
|
||||
* in such transactions automatically. Using either of those or going through
|
||||
* implementation for a single Hibernate {@link SessionFactory}.
|
||||
* Binds a Hibernate Session from the specified factory to the thread,
|
||||
* potentially allowing for one thread-bound Session per factory.
|
||||
* {@code SessionFactory.getCurrentSession()} is required for Hibernate
|
||||
* access code that needs to support this transaction handling mechanism.
|
||||
* access code that needs to support this transaction handling mechanism,
|
||||
* with the SessionFactory being configured with {@link SpringSessionContext}.
|
||||
*
|
||||
* <p>Supports custom isolation levels, and timeouts that get applied as
|
||||
* Hibernate transaction timeouts.
|
||||
@@ -78,27 +75,12 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
*
|
||||
* <p>Note: To be able to register a DataSource's Connection for plain JDBC code,
|
||||
* this instance needs to be aware of the DataSource ({@link #setDataSource}).
|
||||
* The given DataSource should obviously match the one used by the given
|
||||
* SessionFactory. To achieve this, configure both to the same JNDI DataSource,
|
||||
* or preferably create the SessionFactory with {@link LocalSessionFactoryBean} and
|
||||
* a local DataSource (which will be autodetected by this transaction manager).
|
||||
* The given DataSource should obviously match the one used by the given SessionFactory.
|
||||
*
|
||||
* <p>JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager})
|
||||
* is necessary for accessing multiple transactional resources within the same
|
||||
* transaction. The DataSource that Hibernate uses needs to be JTA-enabled in
|
||||
* such a scenario (see container setup). Normally, JTA setup for Hibernate is
|
||||
* somewhat container-specific due to the JTA TransactionManager lookup, required
|
||||
* for proper transactional handling of the SessionFactory-level read-write cache.
|
||||
*
|
||||
* <p>Fortunately, there is an easier way with Spring: {@link SessionFactoryUtils}
|
||||
* (and thus {@link HibernateTemplate}) registers synchronizations with Spring's
|
||||
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}
|
||||
* (as used by {@link org.springframework.transaction.jta.JtaTransactionManager}),
|
||||
* for proper after-completion callbacks. Therefore, as long as Spring's
|
||||
* JtaTransactionManager drives the JTA transactions, Hibernate does not require
|
||||
* any special configuration for proper JTA participation. Note that there are
|
||||
* special restrictions with EJB CMT and restrictive JTA subsystems: See
|
||||
* {@link org.springframework.transaction.jta.JtaTransactionManager}'s javadoc for details.
|
||||
* such a scenario (see container setup).
|
||||
*
|
||||
* <p>This transaction manager supports nested transactions via JDBC 3.0 Savepoints.
|
||||
* The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"} flag defaults
|
||||
@@ -110,27 +92,17 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* support nested transactions! Hence, do not expect Hibernate access code to
|
||||
* semantically participate in a nested transaction.</i>
|
||||
*
|
||||
* <p>Requires Hibernate 3.6.x, as of Spring 4.0.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @since 4.2
|
||||
* @see #setSessionFactory
|
||||
* @see #setDataSource
|
||||
* @see LocalSessionFactoryBean
|
||||
* @see SessionFactoryUtils#getSession
|
||||
* @see SessionFactoryUtils#applyTransactionTimeout
|
||||
* @see SessionFactoryUtils#releaseSession
|
||||
* @see HibernateTemplate
|
||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
|
||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#applyTransactionTimeout
|
||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
|
||||
* @see SessionFactory#getCurrentSession()
|
||||
* @see DataSourceUtils#getConnection
|
||||
* @see DataSourceUtils#releaseConnection
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
||||
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
|
||||
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
|
||||
@@ -143,16 +115,12 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
|
||||
private boolean prepareConnection = true;
|
||||
|
||||
private boolean allowResultAccessAfterCompletion = false;
|
||||
|
||||
private boolean hibernateManagedSession = false;
|
||||
|
||||
private boolean earlyFlushBeforeCommit = false;
|
||||
|
||||
private Object entityInterceptor;
|
||||
|
||||
private SQLExceptionTranslator jdbcExceptionTranslator;
|
||||
|
||||
private SQLExceptionTranslator defaultJdbcExceptionTranslator;
|
||||
|
||||
/**
|
||||
* Just needed for entityInterceptorBeanName.
|
||||
* @see #setEntityInterceptorBeanName
|
||||
@@ -210,10 +178,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
* nevertheless a TransactionAwareDataSourceProxy passed in, it will be
|
||||
* unwrapped to extract its target DataSource.
|
||||
* @see #setAutodetectDataSource
|
||||
* @see LocalDataSourceConnectionProvider
|
||||
* @see LocalSessionFactoryBean#setDataSource
|
||||
* @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
|
||||
* @see org.springframework.jdbc.datasource.DataSourceUtils
|
||||
* @see TransactionAwareDataSourceProxy
|
||||
* @see DataSourceUtils
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
||||
*/
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
@@ -241,7 +207,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
* <p>Can be turned off to deliberately ignore an available DataSource, in order
|
||||
* to not expose Hibernate transactions as JDBC transactions for that DataSource.
|
||||
* @see #setDataSource
|
||||
* @see LocalSessionFactoryBean#setDataSource
|
||||
*/
|
||||
public void setAutodetectDataSource(boolean autodetectDataSource) {
|
||||
this.autodetectDataSource = autodetectDataSource;
|
||||
@@ -257,29 +222,43 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
* call {@code Connection.setReadOnly(true)} for read-only transactions
|
||||
* anymore either. If this flag is turned off, no cleanup of a JDBC Connection
|
||||
* is required after a transaction, since no Connection settings will get modified.
|
||||
* @see java.sql.Connection#setTransactionIsolation
|
||||
* @see java.sql.Connection#setReadOnly
|
||||
* @see Connection#setTransactionIsolation
|
||||
* @see Connection#setReadOnly
|
||||
*/
|
||||
public void setPrepareConnection(boolean prepareConnection) {
|
||||
this.prepareConnection = prepareConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to allow result access after completion, typically via Hibernate's
|
||||
* ScrollableResults mechanism.
|
||||
* <p>Default is "false". Turning this flag on enforces over-commit holdability on the
|
||||
* underlying JDBC Connection (if {@link #prepareConnection "prepareConnection"} is on)
|
||||
* and skips the disconnect-on-completion step.
|
||||
* @see Connection#setHoldability
|
||||
* @see ResultSet#HOLD_CURSORS_OVER_COMMIT
|
||||
* @see #disconnectOnCompletion(Session)
|
||||
*/
|
||||
public void setAllowResultAccessAfterCompletion(boolean allowResultAccessAfterCompletion) {
|
||||
this.allowResultAccessAfterCompletion = allowResultAccessAfterCompletion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to operate on a Hibernate-managed Session instead of a
|
||||
* Spring-managed Session, that is, whether to obtain the Session through
|
||||
* Hibernate's {@link org.hibernate.SessionFactory#getCurrentSession()}
|
||||
* instead of {@link org.hibernate.SessionFactory#openSession()} (with a Spring
|
||||
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}
|
||||
* Hibernate's {@link SessionFactory#getCurrentSession()}
|
||||
* instead of {@link SessionFactory#openSession()} (with a Spring
|
||||
* {@link TransactionSynchronizationManager}
|
||||
* check preceding it).
|
||||
* <p>Default is "false", i.e. using a Spring-managed Session: taking the current
|
||||
* thread-bound Session if available (e.g. in an Open-Session-in-View scenario),
|
||||
* creating a new Session for the current transaction otherwise.
|
||||
* <p>Switch this flag to "true" in order to enforce use of a Hibernate-managed Session.
|
||||
* Note that this requires {@link org.hibernate.SessionFactory#getCurrentSession()}
|
||||
* Note that this requires {@link SessionFactory#getCurrentSession()}
|
||||
* to always return a proper Session when called for a Spring-managed transaction;
|
||||
* transaction begin will fail if the {@code getCurrentSession()} call fails.
|
||||
* <p>This mode will typically be used in combination with a custom Hibernate
|
||||
* {@link org.hibernate.context.CurrentSessionContext} implementation that stores
|
||||
* {@link org.hibernate.context.spi.CurrentSessionContext} implementation that stores
|
||||
* Sessions in a place other than Spring's TransactionSynchronizationManager.
|
||||
* It may also be used in combination with Spring's Open-Session-in-View support
|
||||
* (using Spring's default {@link SpringSessionContext}), in which case it subtly
|
||||
@@ -292,23 +271,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
this.hibernateManagedSession = hibernateManagedSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to perform an early flush before proceeding with a commit.
|
||||
* <p>Default is "false", performing an implicit flush as part of the actual
|
||||
* commit step. Switch this to "true" in order to enforce an explicit early
|
||||
* flush right <i>before</i> the actual commit step.
|
||||
* <p>An early flush happens before the before-commit synchronization phase,
|
||||
* making flushed state visible to {@code beforeCommit} callbacks of registered
|
||||
* {@link org.springframework.transaction.support.TransactionSynchronization}
|
||||
* objects. Such explicit flush behavior is consistent with Spring-driven
|
||||
* flushing in a JTA transaction environment, so may also get enforced for
|
||||
* consistency with JTA transaction behavior.
|
||||
* @see #prepareForCommit
|
||||
*/
|
||||
public void setEarlyFlushBeforeCommit(boolean earlyFlushBeforeCommit) {
|
||||
this.earlyFlushBeforeCommit = earlyFlushBeforeCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean name of a Hibernate entity interceptor that allows to inspect
|
||||
* and change property values before writing to and reading from the database.
|
||||
@@ -333,12 +295,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
* Will get applied to any new Session created by this transaction manager.
|
||||
* <p>Such an interceptor can either be set at the SessionFactory level,
|
||||
* i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
|
||||
* HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
|
||||
* It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
|
||||
* to avoid repeated configuration and guarantee consistent behavior in transactions.
|
||||
* HibernateTransactionManager.
|
||||
* @see LocalSessionFactoryBean#setEntityInterceptor
|
||||
* @see HibernateTemplate#setEntityInterceptor
|
||||
* @see HibernateInterceptor#setEntityInterceptor
|
||||
*/
|
||||
public void setEntityInterceptor(Interceptor entityInterceptor) {
|
||||
this.entityInterceptor = entityInterceptor;
|
||||
@@ -370,28 +328,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JDBC exception translator for this transaction manager.
|
||||
* <p>Applied to any SQLException root cause of a Hibernate JDBCException that
|
||||
* is thrown on flush, overriding Hibernate's default SQLException translation
|
||||
* (which is based on Hibernate's Dialect for a specific target database).
|
||||
* @param jdbcExceptionTranslator the exception translator
|
||||
* @see java.sql.SQLException
|
||||
* @see org.hibernate.JDBCException
|
||||
* @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
|
||||
* @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
|
||||
*/
|
||||
public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
|
||||
this.jdbcExceptionTranslator = jdbcExceptionTranslator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JDBC exception translator for this transaction manager, if any.
|
||||
*/
|
||||
public SQLExceptionTranslator getJdbcExceptionTranslator() {
|
||||
return this.jdbcExceptionTranslator;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bean factory just needs to be known for resolving entity interceptor
|
||||
* bean names. It does not need to be set for any other mode of operation.
|
||||
@@ -440,17 +376,15 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
||||
if (sessionHolder != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found thread-bound Session [" +
|
||||
SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");
|
||||
logger.debug("Found thread-bound Session [" + sessionHolder.getSession() + "] for Hibernate transaction");
|
||||
}
|
||||
txObject.setSessionHolder(sessionHolder);
|
||||
}
|
||||
else if (this.hibernateManagedSession) {
|
||||
try {
|
||||
Session session = getSessionFactory().getCurrentSession();
|
||||
Session session = this.sessionFactory.getCurrentSession();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found Hibernate-managed Session [" +
|
||||
SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");
|
||||
logger.debug("Found Hibernate-managed Session [" + session + "] for Spring-managed transaction");
|
||||
}
|
||||
txObject.setExistingSession(session);
|
||||
}
|
||||
@@ -477,6 +411,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void doBegin(Object transaction, TransactionDefinition definition) {
|
||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
||||
|
||||
@@ -494,10 +429,10 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
|
||||
Interceptor entityInterceptor = getEntityInterceptor();
|
||||
Session newSession = (entityInterceptor != null ?
|
||||
getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());
|
||||
getSessionFactory().withOptions().interceptor(entityInterceptor).openSession() :
|
||||
getSessionFactory().openSession());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +
|
||||
"] for Hibernate transaction");
|
||||
logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
|
||||
}
|
||||
txObject.setSession(newSession);
|
||||
}
|
||||
@@ -507,12 +442,18 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
|
||||
// We're allowed to change the transaction settings of the JDBC Connection.
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
"Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
|
||||
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
|
||||
}
|
||||
Connection con = session.connection();
|
||||
Connection con = ((SessionImplementor) session).connection();
|
||||
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
|
||||
txObject.setPreviousIsolationLevel(previousIsolationLevel);
|
||||
if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
|
||||
int currentHoldability = con.getHoldability();
|
||||
if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
|
||||
txObject.setPreviousHoldability(currentHoldability);
|
||||
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not allowed to change the transaction settings of the JDBC Connection.
|
||||
@@ -521,13 +462,10 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
throw new InvalidIsolationLevelException(
|
||||
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
|
||||
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
|
||||
"Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default). " +
|
||||
"Make sure that your LocalSessionFactoryBean actually uses SpringTransactionFactory: Your " +
|
||||
"Hibernate properties should *not* include a 'hibernate.transaction.factory_class' property!");
|
||||
"Hibernate connection release mode is set to 'on_close' (the default for JDBC).");
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
"Not preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
|
||||
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,8 +476,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
|
||||
if (!definition.isReadOnly() && !txObject.isNewSession()) {
|
||||
// We need AUTO or COMMIT for a non-read-only transaction.
|
||||
FlushMode flushMode = session.getFlushMode();
|
||||
if (flushMode.lessThan(FlushMode.COMMIT)) {
|
||||
FlushMode flushMode = SessionFactoryUtils.getFlushMode(session);
|
||||
if (FlushMode.MANUAL.equals(flushMode)) {
|
||||
session.setFlushMode(FlushMode.AUTO);
|
||||
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
|
||||
}
|
||||
@@ -566,7 +504,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
|
||||
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
|
||||
if (getDataSource() != null) {
|
||||
Connection con = session.connection();
|
||||
Connection con = ((SessionImplementor) session).connection();
|
||||
ConnectionHolder conHolder = new ConnectionHolder(con);
|
||||
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
|
||||
conHolder.setTimeoutInSeconds(timeout);
|
||||
@@ -588,7 +526,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
catch (Throwable ex) {
|
||||
if (txObject.isNewSession()) {
|
||||
try {
|
||||
if (session.getTransaction().isActive()) {
|
||||
if (session.getTransaction().getStatus() == TransactionStatus.ACTIVE) {
|
||||
session.getTransaction().rollback();
|
||||
}
|
||||
}
|
||||
@@ -632,32 +570,12 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareForCommit(DefaultTransactionStatus status) {
|
||||
if (this.earlyFlushBeforeCommit && status.isNewTransaction()) {
|
||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
||||
Session session = txObject.getSessionHolder().getSession();
|
||||
if (!session.getFlushMode().lessThan(FlushMode.COMMIT)) {
|
||||
logger.debug("Performing an early flush for Hibernate transaction");
|
||||
try {
|
||||
session.flush();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw convertHibernateAccessException(ex);
|
||||
}
|
||||
finally {
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doCommit(DefaultTransactionStatus status) {
|
||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
||||
if (status.isDebug()) {
|
||||
logger.debug("Committing Hibernate transaction on Session [" +
|
||||
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
|
||||
txObject.getSessionHolder().getSession() + "]");
|
||||
}
|
||||
try {
|
||||
txObject.getSessionHolder().getTransaction().commit();
|
||||
@@ -677,7 +595,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
||||
if (status.isDebug()) {
|
||||
logger.debug("Rolling back Hibernate transaction on Session [" +
|
||||
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
|
||||
txObject.getSessionHolder().getSession() + "]");
|
||||
}
|
||||
try {
|
||||
txObject.getSessionHolder().getTransaction().rollback();
|
||||
@@ -703,12 +621,13 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
|
||||
if (status.isDebug()) {
|
||||
logger.debug("Setting Hibernate transaction on Session [" +
|
||||
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "] rollback-only");
|
||||
txObject.getSessionHolder().getSession() + "] rollback-only");
|
||||
}
|
||||
txObject.setRollbackOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void doCleanupAfterCompletion(Object transaction) {
|
||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
||||
|
||||
@@ -723,62 +642,92 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
}
|
||||
|
||||
Session session = txObject.getSessionHolder().getSession();
|
||||
if (this.prepareConnection && session.isConnected() && isSameConnectionForEntireSession(session)) {
|
||||
if (this.prepareConnection && isPhysicallyConnected(session)) {
|
||||
// We're running with connection release mode "on_close": We're able to reset
|
||||
// the isolation level and/or read-only flag of the JDBC Connection here.
|
||||
// Else, we need to rely on the connection pool to perform proper cleanup.
|
||||
try {
|
||||
Connection con = session.connection();
|
||||
Connection con = ((SessionImplementor) session).connection();
|
||||
Integer previousHoldability = txObject.getPreviousHoldability();
|
||||
if (previousHoldability != null) {
|
||||
con.setHoldability(previousHoldability);
|
||||
}
|
||||
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
logger.debug("Could not access JDBC Connection of Hibernate Session", ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Could not reset JDBC Connection after transaction", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (txObject.isNewSession()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Closing Hibernate Session [" + SessionFactoryUtils.toString(session) +
|
||||
"] after transaction");
|
||||
logger.debug("Closing Hibernate Session [" + session + "] after transaction");
|
||||
}
|
||||
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
|
||||
SessionFactoryUtils.closeSession(session);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Not closing pre-bound Hibernate Session [" +
|
||||
SessionFactoryUtils.toString(session) + "] after transaction");
|
||||
logger.debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
|
||||
}
|
||||
if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
|
||||
session.setFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
|
||||
}
|
||||
if (!this.hibernateManagedSession) {
|
||||
session.disconnect();
|
||||
if (!this.allowResultAccessAfterCompletion && !this.hibernateManagedSession) {
|
||||
disconnectOnCompletion(session);
|
||||
}
|
||||
}
|
||||
txObject.getSessionHolder().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect a pre-existing Hibernate Session on transaction completion,
|
||||
* returning its database connection but preserving its entity state.
|
||||
* <p>The default implementation simply calls {@link Session#disconnect()}.
|
||||
* Subclasses may override this with a no-op or with fine-tuned disconnection logic.
|
||||
* @param session the Hibernate Session to disconnect
|
||||
* @see Session#disconnect()
|
||||
*/
|
||||
protected void disconnectOnCompletion(Session session) {
|
||||
session.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given Hibernate Session will always hold the same
|
||||
* JDBC Connection. This is used to check whether the transaction manager
|
||||
* can safely prepare and clean up the JDBC Connection used for a transaction.
|
||||
* <p>Default implementation checks the Session's connection release mode
|
||||
* to be "on_close". Unfortunately, this requires casting to SessionImpl,
|
||||
* as of Hibernate 3.1. If that cast doesn't work, we'll simply assume
|
||||
* we're safe and return {@code true}.
|
||||
* <p>The default implementation checks the Session's connection release mode
|
||||
* to be "on_close".
|
||||
* @param session the Hibernate Session to check
|
||||
* @see org.hibernate.impl.SessionImpl#getConnectionReleaseMode()
|
||||
* @see org.hibernate.ConnectionReleaseMode#ON_CLOSE
|
||||
* @see ConnectionReleaseMode#ON_CLOSE
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected boolean isSameConnectionForEntireSession(Session session) {
|
||||
if (!(session instanceof SessionImpl)) {
|
||||
if (!(session instanceof SessionImplementor)) {
|
||||
// The best we can do is to assume we're safe.
|
||||
return true;
|
||||
}
|
||||
ConnectionReleaseMode releaseMode = ((SessionImpl) session).getConnectionReleaseMode();
|
||||
ConnectionReleaseMode releaseMode =
|
||||
((SessionImplementor) session).getJdbcCoordinator().getConnectionReleaseMode();
|
||||
return ConnectionReleaseMode.ON_CLOSE.equals(releaseMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given Session is (still) physically connected
|
||||
* to the database, that is, holds an active JDBC Connection internally.
|
||||
* @param session the Hibernate Session to check
|
||||
* @see #isSameConnectionForEntireSession(Session)
|
||||
*/
|
||||
protected boolean isPhysicallyConnected(Session session) {
|
||||
if (!(session instanceof SessionImplementor)) {
|
||||
// The best we can do is to check whether we're logically connected.
|
||||
return session.isConnected();
|
||||
}
|
||||
return ((SessionImplementor) session).getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the given HibernateException to an appropriate exception
|
||||
@@ -788,48 +737,11 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
* @param ex HibernateException that occurred
|
||||
* @return a corresponding DataAccessException
|
||||
* @see SessionFactoryUtils#convertHibernateAccessException
|
||||
* @see #setJdbcExceptionTranslator
|
||||
*/
|
||||
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
|
||||
if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
|
||||
return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
|
||||
}
|
||||
else if (GenericJDBCException.class == ex.getClass()) {
|
||||
return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator());
|
||||
}
|
||||
return SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given Hibernate JDBCException to an appropriate exception
|
||||
* from the {@code org.springframework.dao} hierarchy, using the
|
||||
* given SQLExceptionTranslator.
|
||||
* @param ex Hibernate JDBCException that occurred
|
||||
* @param translator the SQLExceptionTranslator to use
|
||||
* @return a corresponding DataAccessException
|
||||
*/
|
||||
protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) {
|
||||
return translator.translate("Hibernate flushing: " + ex.getMessage(), ex.getSQL(), ex.getSQLException());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a default SQLExceptionTranslator, lazily creating it if necessary.
|
||||
* <p>Creates a default
|
||||
* {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator}
|
||||
* for the SessionFactory's underlying DataSource.
|
||||
*/
|
||||
protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() {
|
||||
if (this.defaultJdbcExceptionTranslator == null) {
|
||||
if (getDataSource() != null) {
|
||||
this.defaultJdbcExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(getDataSource());
|
||||
}
|
||||
else {
|
||||
this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory());
|
||||
}
|
||||
}
|
||||
return this.defaultJdbcExceptionTranslator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hibernate transaction object, representing a SessionHolder.
|
||||
@@ -843,6 +755,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
|
||||
private boolean newSession;
|
||||
|
||||
private Integer previousHoldability;
|
||||
|
||||
public void setSession(Session session) {
|
||||
this.sessionHolder = new SessionHolder(session);
|
||||
this.newSessionHolder = true;
|
||||
@@ -873,12 +787,21 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
return this.newSession;
|
||||
}
|
||||
|
||||
public void setPreviousHoldability(Integer previousHoldability) {
|
||||
this.previousHoldability = previousHoldability;
|
||||
}
|
||||
|
||||
public Integer getPreviousHoldability() {
|
||||
return this.previousHoldability;
|
||||
}
|
||||
|
||||
public boolean hasSpringManagedTransaction() {
|
||||
return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);
|
||||
}
|
||||
|
||||
public boolean hasHibernateManagedTransaction() {
|
||||
return (this.sessionHolder != null && this.sessionHolder.getSession().getTransaction().isActive());
|
||||
return (this.sessionHolder != null &&
|
||||
this.sessionHolder.getSession().getTransaction().getStatus() == TransactionStatus.ACTIVE);
|
||||
}
|
||||
|
||||
public void setRollbackOnly() {
|
||||
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.hibernate5;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
||||
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
|
||||
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} that creates a Hibernate
|
||||
* {@link SessionFactory}. This is the usual way to set up a shared
|
||||
* Hibernate SessionFactory in a Spring application context; the SessionFactory can
|
||||
* then be passed to Hibernate-based data access objects via dependency injection.
|
||||
*
|
||||
* <p>Compatible with Hibernate 5.0/5.1 as well as 5.2, as of Spring 4.3.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @see #setDataSource
|
||||
* @see #setPackagesToScan
|
||||
* @see LocalSessionFactoryBuilder
|
||||
*/
|
||||
public class LocalSessionFactoryBean extends HibernateExceptionTranslator
|
||||
implements FactoryBean<SessionFactory>, ResourceLoaderAware, InitializingBean, DisposableBean {
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
private Resource[] configLocations;
|
||||
|
||||
private String[] mappingResources;
|
||||
|
||||
private Resource[] mappingLocations;
|
||||
|
||||
private Resource[] cacheableMappingLocations;
|
||||
|
||||
private Resource[] mappingJarLocations;
|
||||
|
||||
private Resource[] mappingDirectoryLocations;
|
||||
|
||||
private Interceptor entityInterceptor;
|
||||
|
||||
private ImplicitNamingStrategy implicitNamingStrategy;
|
||||
|
||||
private PhysicalNamingStrategy physicalNamingStrategy;
|
||||
|
||||
private Object jtaTransactionManager;
|
||||
|
||||
private MultiTenantConnectionProvider multiTenantConnectionProvider;
|
||||
|
||||
private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
|
||||
|
||||
private TypeFilter[] entityTypeFilters;
|
||||
|
||||
private Properties hibernateProperties;
|
||||
|
||||
private Class<?>[] annotatedClasses;
|
||||
|
||||
private String[] annotatedPackages;
|
||||
|
||||
private String[] packagesToScan;
|
||||
|
||||
private AsyncTaskExecutor bootstrapExecutor;
|
||||
|
||||
private MetadataSources metadataSources;
|
||||
|
||||
private ResourcePatternResolver resourcePatternResolver;
|
||||
|
||||
private Configuration configuration;
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the DataSource to be used by the SessionFactory.
|
||||
* If set, this will override corresponding settings in Hibernate properties.
|
||||
* <p>If this is set, the Hibernate settings should not define
|
||||
* a connection provider to avoid meaningless double configuration.
|
||||
*/
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the location of a single Hibernate XML config file, for example as
|
||||
* classpath resource "classpath:hibernate.cfg.xml".
|
||||
* <p>Note: Can be omitted when all necessary properties and mapping
|
||||
* resources are specified locally via this bean.
|
||||
* @see Configuration#configure(java.net.URL)
|
||||
*/
|
||||
public void setConfigLocation(Resource configLocation) {
|
||||
this.configLocations = new Resource[] {configLocation};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the locations of multiple Hibernate XML config files, for example as
|
||||
* classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml".
|
||||
* <p>Note: Can be omitted when all necessary properties and mapping
|
||||
* resources are specified locally via this bean.
|
||||
* @see Configuration#configure(java.net.URL)
|
||||
*/
|
||||
public void setConfigLocations(Resource... configLocations) {
|
||||
this.configLocations = configLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Hibernate mapping resources to be found in the class path,
|
||||
* like "example.hbm.xml" or "mypackage/example.hbm.xml".
|
||||
* Analogous to mapping entries in a Hibernate XML config file.
|
||||
* Alternative to the more generic setMappingLocations method.
|
||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
||||
* or to specify all mappings locally.
|
||||
* @see #setMappingLocations
|
||||
* @see Configuration#addResource
|
||||
*/
|
||||
public void setMappingResources(String... mappingResources) {
|
||||
this.mappingResources = mappingResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set locations of Hibernate mapping files, for example as classpath
|
||||
* resource "classpath:example.hbm.xml". Supports any resource location
|
||||
* via Spring's resource abstraction, for example relative paths like
|
||||
* "WEB-INF/mappings/example.hbm.xml" when running in an application context.
|
||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
||||
* or to specify all mappings locally.
|
||||
* @see Configuration#addInputStream
|
||||
*/
|
||||
public void setMappingLocations(Resource... mappingLocations) {
|
||||
this.mappingLocations = mappingLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set locations of cacheable Hibernate mapping files, for example as web app
|
||||
* resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location
|
||||
* via Spring's resource abstraction, as long as the resource can be resolved
|
||||
* in the file system.
|
||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
||||
* or to specify all mappings locally.
|
||||
* @see Configuration#addCacheableFile(File)
|
||||
*/
|
||||
public void setCacheableMappingLocations(Resource... cacheableMappingLocations) {
|
||||
this.cacheableMappingLocations = cacheableMappingLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set locations of jar files that contain Hibernate mapping resources,
|
||||
* like "WEB-INF/lib/example.hbm.jar".
|
||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
||||
* or to specify all mappings locally.
|
||||
* @see Configuration#addJar(File)
|
||||
*/
|
||||
public void setMappingJarLocations(Resource... mappingJarLocations) {
|
||||
this.mappingJarLocations = mappingJarLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set locations of directories that contain Hibernate mapping resources,
|
||||
* like "WEB-INF/mappings".
|
||||
* <p>Can be used to add to mappings from a Hibernate XML config file,
|
||||
* or to specify all mappings locally.
|
||||
* @see Configuration#addDirectory(File)
|
||||
*/
|
||||
public void setMappingDirectoryLocations(Resource... mappingDirectoryLocations) {
|
||||
this.mappingDirectoryLocations = mappingDirectoryLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Hibernate entity interceptor that allows to inspect and change
|
||||
* property values before writing to and reading from the database.
|
||||
* Will get applied to any new Session created by this factory.
|
||||
* @see Configuration#setInterceptor
|
||||
*/
|
||||
public void setEntityInterceptor(Interceptor entityInterceptor) {
|
||||
this.entityInterceptor = entityInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Hibernate 5.0 ImplicitNamingStrategy for the SessionFactory.
|
||||
* @see Configuration#setImplicitNamingStrategy
|
||||
*/
|
||||
public void setImplicitNamingStrategy(ImplicitNamingStrategy implicitNamingStrategy) {
|
||||
this.implicitNamingStrategy = implicitNamingStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Hibernate 5.0 PhysicalNamingStrategy for the SessionFactory.
|
||||
* @see Configuration#setPhysicalNamingStrategy
|
||||
*/
|
||||
public void setPhysicalNamingStrategy(PhysicalNamingStrategy physicalNamingStrategy) {
|
||||
this.physicalNamingStrategy = physicalNamingStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
|
||||
* or the JTA {@link javax.transaction.TransactionManager} to be used with Hibernate,
|
||||
* if any. Implicitly sets up {@code JtaPlatform}.
|
||||
* @see LocalSessionFactoryBuilder#setJtaTransactionManager
|
||||
*/
|
||||
public void setJtaTransactionManager(Object jtaTransactionManager) {
|
||||
this.jtaTransactionManager = jtaTransactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link MultiTenantConnectionProvider} to be passed on to the SessionFactory.
|
||||
* @since 4.3
|
||||
* @see LocalSessionFactoryBuilder#setMultiTenantConnectionProvider
|
||||
*/
|
||||
public void setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) {
|
||||
this.multiTenantConnectionProvider = multiTenantConnectionProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link CurrentTenantIdentifierResolver} to be passed on to the SessionFactory.
|
||||
* @see LocalSessionFactoryBuilder#setCurrentTenantIdentifierResolver
|
||||
*/
|
||||
public void setCurrentTenantIdentifierResolver(CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {
|
||||
this.currentTenantIdentifierResolver = currentTenantIdentifierResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify custom type filters for Spring-based scanning for entity classes.
|
||||
* <p>Default is to search all specified packages for classes annotated with
|
||||
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
|
||||
* or {@code @javax.persistence.MappedSuperclass}.
|
||||
* @see #setPackagesToScan
|
||||
*/
|
||||
public void setEntityTypeFilters(TypeFilter... entityTypeFilters) {
|
||||
this.entityTypeFilters = entityTypeFilters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Hibernate properties, such as "hibernate.dialect".
|
||||
* <p>Note: Do not specify a transaction provider here when using
|
||||
* Spring-driven transactions. It is also advisable to omit connection
|
||||
* provider settings and use a Spring-set DataSource instead.
|
||||
* @see #setDataSource
|
||||
*/
|
||||
public void setHibernateProperties(Properties hibernateProperties) {
|
||||
this.hibernateProperties = hibernateProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Hibernate properties, if any. Mainly available for
|
||||
* configuration through property paths that specify individual keys.
|
||||
*/
|
||||
public Properties getHibernateProperties() {
|
||||
if (this.hibernateProperties == null) {
|
||||
this.hibernateProperties = new Properties();
|
||||
}
|
||||
return this.hibernateProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify annotated entity classes to register with this Hibernate SessionFactory.
|
||||
* @see Configuration#addAnnotatedClass(Class)
|
||||
*/
|
||||
public void setAnnotatedClasses(Class<?>... annotatedClasses) {
|
||||
this.annotatedClasses = annotatedClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the names of annotated packages, for which package-level
|
||||
* annotation metadata will be read.
|
||||
* @see Configuration#addPackage(String)
|
||||
*/
|
||||
public void setAnnotatedPackages(String... annotatedPackages) {
|
||||
this.annotatedPackages = annotatedPackages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify packages to search for autodetection of your entity classes in the
|
||||
* classpath. This is analogous to Spring's component-scan feature
|
||||
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
|
||||
*/
|
||||
public void setPackagesToScan(String... packagesToScan) {
|
||||
this.packagesToScan = packagesToScan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify an asynchronous executor for background bootstrapping,
|
||||
* e.g. a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}.
|
||||
* <p>{@code SessionFactory} initialization will then switch into background
|
||||
* bootstrap mode, with a {@code SessionFactory} proxy immediately returned for
|
||||
* injection purposes instead of waiting for Hibernate's bootstrapping to complete.
|
||||
* However, note that the first actual call to a {@code SessionFactory} method will
|
||||
* then block until Hibernate's bootstrapping completed, if not ready by then.
|
||||
* For maximum benefit, make sure to avoid early {@code SessionFactory} calls
|
||||
* in init methods of related beans, even for metadata introspection purposes.
|
||||
* @see LocalSessionFactoryBuilder#buildSessionFactory(AsyncTaskExecutor)
|
||||
* @since 4.3
|
||||
*/
|
||||
public void setBootstrapExecutor(AsyncTaskExecutor bootstrapExecutor) {
|
||||
this.bootstrapExecutor = bootstrapExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a Hibernate {@link MetadataSources} service to use (e.g. reusing an
|
||||
* existing one), potentially populated with a custom Hibernate bootstrap
|
||||
* {@link org.hibernate.service.ServiceRegistry} as well.
|
||||
* @since 4.3
|
||||
*/
|
||||
public void setMetadataSources(MetadataSources metadataSources) {
|
||||
Assert.notNull(metadataSources, "MetadataSources must not be null");
|
||||
this.metadataSources = metadataSources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the Hibernate {@link MetadataSources} to use.
|
||||
* <p>Can also be externally called to initialize and pre-populate a {@link MetadataSources}
|
||||
* instance which is then going to be used for {@link SessionFactory} building.
|
||||
* @return the MetadataSources to use (never {@code null})
|
||||
* @since 4.3
|
||||
* @see LocalSessionFactoryBuilder#LocalSessionFactoryBuilder(DataSource, ResourceLoader, MetadataSources)
|
||||
*/
|
||||
public MetadataSources getMetadataSources() {
|
||||
if (this.metadataSources == null) {
|
||||
BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder();
|
||||
if (this.resourcePatternResolver != null) {
|
||||
builder = builder.applyClassLoader(this.resourcePatternResolver.getClassLoader());
|
||||
}
|
||||
this.metadataSources = new MetadataSources(builder.build());
|
||||
}
|
||||
return this.metadataSources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a Spring {@link ResourceLoader} to use for Hibernate metadata.
|
||||
* @param resourceLoader the ResourceLoader to use (never {@code null})
|
||||
*/
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the Spring {@link ResourceLoader} to use for Hibernate metadata.
|
||||
* @return the ResourceLoader to use (never {@code null})
|
||||
* @since 4.3
|
||||
*/
|
||||
public ResourceLoader getResourceLoader() {
|
||||
if (this.resourcePatternResolver == null) {
|
||||
this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
}
|
||||
return this.resourcePatternResolver;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws IOException {
|
||||
LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(
|
||||
this.dataSource, getResourceLoader(), getMetadataSources());
|
||||
|
||||
if (this.configLocations != null) {
|
||||
for (Resource resource : this.configLocations) {
|
||||
// Load Hibernate configuration from given location.
|
||||
sfb.configure(resource.getURL());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mappingResources != null) {
|
||||
// Register given Hibernate mapping definitions, contained in resource files.
|
||||
for (String mapping : this.mappingResources) {
|
||||
Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader());
|
||||
sfb.addInputStream(mr.getInputStream());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mappingLocations != null) {
|
||||
// Register given Hibernate mapping definitions, contained in resource files.
|
||||
for (Resource resource : this.mappingLocations) {
|
||||
sfb.addInputStream(resource.getInputStream());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.cacheableMappingLocations != null) {
|
||||
// Register given cacheable Hibernate mapping definitions, read from the file system.
|
||||
for (Resource resource : this.cacheableMappingLocations) {
|
||||
sfb.addCacheableFile(resource.getFile());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mappingJarLocations != null) {
|
||||
// Register given Hibernate mapping definitions, contained in jar files.
|
||||
for (Resource resource : this.mappingJarLocations) {
|
||||
sfb.addJar(resource.getFile());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mappingDirectoryLocations != null) {
|
||||
// Register all Hibernate mapping definitions in the given directories.
|
||||
for (Resource resource : this.mappingDirectoryLocations) {
|
||||
File file = resource.getFile();
|
||||
if (!file.isDirectory()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Mapping directory location [" + resource + "] does not denote a directory");
|
||||
}
|
||||
sfb.addDirectory(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.entityInterceptor != null) {
|
||||
sfb.setInterceptor(this.entityInterceptor);
|
||||
}
|
||||
|
||||
if (this.implicitNamingStrategy != null) {
|
||||
sfb.setImplicitNamingStrategy(this.implicitNamingStrategy);
|
||||
}
|
||||
|
||||
if (this.physicalNamingStrategy != null) {
|
||||
sfb.setPhysicalNamingStrategy(this.physicalNamingStrategy);
|
||||
}
|
||||
|
||||
if (this.jtaTransactionManager != null) {
|
||||
sfb.setJtaTransactionManager(this.jtaTransactionManager);
|
||||
}
|
||||
|
||||
if (this.multiTenantConnectionProvider != null) {
|
||||
sfb.setMultiTenantConnectionProvider(this.multiTenantConnectionProvider);
|
||||
}
|
||||
|
||||
if (this.currentTenantIdentifierResolver != null) {
|
||||
sfb.setCurrentTenantIdentifierResolver(this.currentTenantIdentifierResolver);
|
||||
}
|
||||
|
||||
if (this.entityTypeFilters != null) {
|
||||
sfb.setEntityTypeFilters(this.entityTypeFilters);
|
||||
}
|
||||
|
||||
if (this.hibernateProperties != null) {
|
||||
sfb.addProperties(this.hibernateProperties);
|
||||
}
|
||||
|
||||
if (this.annotatedClasses != null) {
|
||||
sfb.addAnnotatedClasses(this.annotatedClasses);
|
||||
}
|
||||
|
||||
if (this.annotatedPackages != null) {
|
||||
sfb.addPackages(this.annotatedPackages);
|
||||
}
|
||||
|
||||
if (this.packagesToScan != null) {
|
||||
sfb.scanPackages(this.packagesToScan);
|
||||
}
|
||||
|
||||
// Build SessionFactory instance.
|
||||
this.configuration = sfb;
|
||||
this.sessionFactory = buildSessionFactory(sfb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this method to perform custom initialization
|
||||
* of the SessionFactory instance, creating it via the given Configuration
|
||||
* object that got prepared by this LocalSessionFactoryBean.
|
||||
* <p>The default implementation invokes LocalSessionFactoryBuilder's buildSessionFactory.
|
||||
* A custom implementation could prepare the instance in a specific way (e.g. applying
|
||||
* a custom ServiceRegistry) or use a custom SessionFactoryImpl subclass.
|
||||
* @param sfb LocalSessionFactoryBuilder prepared by this LocalSessionFactoryBean
|
||||
* @return the SessionFactory instance
|
||||
* @see LocalSessionFactoryBuilder#buildSessionFactory
|
||||
*/
|
||||
protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
|
||||
return (this.bootstrapExecutor != null ? sfb.buildSessionFactory(this.bootstrapExecutor) :
|
||||
sfb.buildSessionFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Hibernate Configuration object used to build the SessionFactory.
|
||||
* Allows for access to configuration metadata stored there (rarely needed).
|
||||
* @throws IllegalStateException if the Configuration object has not been initialized yet
|
||||
*/
|
||||
public final Configuration getConfiguration() {
|
||||
if (this.configuration == null) {
|
||||
throw new IllegalStateException("Configuration not initialized yet");
|
||||
}
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SessionFactory getObject() {
|
||||
return this.sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
this.sessionFactory.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.hibernate5;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.sql.DataSource;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
import org.springframework.core.InfrastructureProxy;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A Spring-provided extension of the standard Hibernate {@link Configuration} class,
|
||||
* adding {@link SpringSessionContext} as a default and providing convenient ways
|
||||
* to specify a DataSource and an application class loader.
|
||||
*
|
||||
* <p>This is designed for programmatic use, e.g. in {@code @Bean} factory methods.
|
||||
* Consider using {@link LocalSessionFactoryBean} for XML bean definition files.
|
||||
*
|
||||
* <p>Compatible with Hibernate 5.0/5.1 as well as 5.2, as of Spring 4.3.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @see LocalSessionFactoryBean
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class LocalSessionFactoryBuilder extends Configuration {
|
||||
|
||||
private static final String RESOURCE_PATTERN = "/**/*.class";
|
||||
|
||||
private static final String PACKAGE_INFO_SUFFIX = ".package-info";
|
||||
|
||||
private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] {
|
||||
new AnnotationTypeFilter(Entity.class, false),
|
||||
new AnnotationTypeFilter(Embeddable.class, false),
|
||||
new AnnotationTypeFilter(MappedSuperclass.class, false)};
|
||||
|
||||
private final TypeFilter CONVERTER_TYPE_FILTER = new AnnotationTypeFilter(Converter.class, false);
|
||||
|
||||
|
||||
private final ResourcePatternResolver resourcePatternResolver;
|
||||
|
||||
private TypeFilter[] entityTypeFilters = DEFAULT_ENTITY_TYPE_FILTERS;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new LocalSessionFactoryBuilder for the given DataSource.
|
||||
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
|
||||
* (may be {@code null})
|
||||
*/
|
||||
public LocalSessionFactoryBuilder(DataSource dataSource) {
|
||||
this(dataSource, new PathMatchingResourcePatternResolver());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new LocalSessionFactoryBuilder for the given DataSource.
|
||||
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
|
||||
* (may be {@code null})
|
||||
* @param classLoader the ClassLoader to load application classes from
|
||||
*/
|
||||
public LocalSessionFactoryBuilder(DataSource dataSource, ClassLoader classLoader) {
|
||||
this(dataSource, new PathMatchingResourcePatternResolver(classLoader));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new LocalSessionFactoryBuilder for the given DataSource.
|
||||
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
|
||||
* (may be {@code null})
|
||||
* @param resourceLoader the ResourceLoader to load application classes from
|
||||
*/
|
||||
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader) {
|
||||
this(dataSource, resourceLoader, new MetadataSources(
|
||||
new BootstrapServiceRegistryBuilder().applyClassLoader(resourceLoader.getClassLoader()).build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new LocalSessionFactoryBuilder for the given DataSource.
|
||||
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
|
||||
* (may be {@code null})
|
||||
* @param resourceLoader the ResourceLoader to load application classes from
|
||||
* @param metadataSources the Hibernate MetadataSources service to use (e.g. reusing an existing one)
|
||||
* @since 4.3
|
||||
*/
|
||||
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader, MetadataSources metadataSources) {
|
||||
super(metadataSources);
|
||||
|
||||
getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());
|
||||
if (dataSource != null) {
|
||||
getProperties().put(Environment.DATASOURCE, dataSource);
|
||||
}
|
||||
|
||||
// Hibernate 5.2: manually enforce connection release mode ON_CLOSE (the former default)
|
||||
getProperties().put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_HOLD");
|
||||
|
||||
getProperties().put(AvailableSettings.CLASSLOADERS, Collections.singleton(resourceLoader.getClassLoader()));
|
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the Spring {@link JtaTransactionManager} or the JTA {@link TransactionManager}
|
||||
* to be used with Hibernate, if any. Allows for using a Spring-managed transaction
|
||||
* manager for Hibernate 5's session and cache synchronization, with the
|
||||
* "hibernate.transaction.jta.platform" automatically set to it.
|
||||
* <p>A passed-in Spring {@link JtaTransactionManager} needs to contain a JTA
|
||||
* {@link TransactionManager} reference to be usable here, except for the WebSphere
|
||||
* case where we'll automatically set {@code WebSphereExtendedJtaPlatform} accordingly.
|
||||
* <p>Note: If this is set, the Hibernate settings should not contain a JTA platform
|
||||
* setting to avoid meaningless double configuration.
|
||||
*/
|
||||
public LocalSessionFactoryBuilder setJtaTransactionManager(Object jtaTransactionManager) {
|
||||
Assert.notNull(jtaTransactionManager, "Transaction manager reference must not be null");
|
||||
|
||||
if (jtaTransactionManager instanceof JtaTransactionManager) {
|
||||
boolean webspherePresent = ClassUtils.isPresent("com.ibm.wsspi.uow.UOWManager", getClass().getClassLoader());
|
||||
if (webspherePresent) {
|
||||
getProperties().put(AvailableSettings.JTA_PLATFORM,
|
||||
"org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform");
|
||||
}
|
||||
else {
|
||||
JtaTransactionManager jtaTm = (JtaTransactionManager) jtaTransactionManager;
|
||||
if (jtaTm.getTransactionManager() == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can only apply JtaTransactionManager which has a TransactionManager reference set");
|
||||
}
|
||||
getProperties().put(AvailableSettings.JTA_PLATFORM,
|
||||
new ConfigurableJtaPlatform(jtaTm.getTransactionManager(), jtaTm.getUserTransaction(),
|
||||
jtaTm.getTransactionSynchronizationRegistry()));
|
||||
}
|
||||
}
|
||||
else if (jtaTransactionManager instanceof TransactionManager) {
|
||||
getProperties().put(AvailableSettings.JTA_PLATFORM,
|
||||
new ConfigurableJtaPlatform((TransactionManager) jtaTransactionManager, null, null));
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown transaction manager type: " + jtaTransactionManager.getClass().getName());
|
||||
}
|
||||
|
||||
// Hibernate 5.2: manually enforce connection release mode AFTER_STATEMENT (the JTA default)
|
||||
getProperties().put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link MultiTenantConnectionProvider} to be passed on to the SessionFactory.
|
||||
* @since 4.3
|
||||
* @see AvailableSettings#MULTI_TENANT_CONNECTION_PROVIDER
|
||||
*/
|
||||
public LocalSessionFactoryBuilder setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) {
|
||||
getProperties().put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify custom type filters for Spring-based scanning for entity classes.
|
||||
* <p>Default is to search all specified packages for classes annotated with
|
||||
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
|
||||
* or {@code @javax.persistence.MappedSuperclass}.
|
||||
* @see #scanPackages
|
||||
*/
|
||||
public LocalSessionFactoryBuilder setEntityTypeFilters(TypeFilter... entityTypeFilters) {
|
||||
this.entityTypeFilters = entityTypeFilters;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given annotated classes in a batch.
|
||||
* @see #addAnnotatedClass
|
||||
* @see #scanPackages
|
||||
*/
|
||||
public LocalSessionFactoryBuilder addAnnotatedClasses(Class<?>... annotatedClasses) {
|
||||
for (Class<?> annotatedClass : annotatedClasses) {
|
||||
addAnnotatedClass(annotatedClass);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given annotated packages in a batch.
|
||||
* @see #addPackage
|
||||
* @see #scanPackages
|
||||
*/
|
||||
public LocalSessionFactoryBuilder addPackages(String... annotatedPackages) {
|
||||
for (String annotatedPackage : annotatedPackages) {
|
||||
addPackage(annotatedPackage);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform Spring-based scanning for entity classes, registering them
|
||||
* as annotated classes with this {@code Configuration}.
|
||||
* @param packagesToScan one or more Java package names
|
||||
* @throws HibernateException if scanning fails for any reason
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public LocalSessionFactoryBuilder scanPackages(String... packagesToScan) throws HibernateException {
|
||||
Set<String> entityClassNames = new TreeSet<String>();
|
||||
Set<String> converterClassNames = new TreeSet<String>();
|
||||
Set<String> packageNames = new TreeSet<String>();
|
||||
try {
|
||||
for (String pkg : packagesToScan) {
|
||||
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
|
||||
ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
|
||||
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
|
||||
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
|
||||
for (Resource resource : resources) {
|
||||
if (resource.isReadable()) {
|
||||
MetadataReader reader = readerFactory.getMetadataReader(resource);
|
||||
String className = reader.getClassMetadata().getClassName();
|
||||
if (matchesEntityTypeFilter(reader, readerFactory)) {
|
||||
entityClassNames.add(className);
|
||||
}
|
||||
else if (CONVERTER_TYPE_FILTER.match(reader, readerFactory)) {
|
||||
converterClassNames.add(className);
|
||||
}
|
||||
else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
|
||||
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new MappingException("Failed to scan classpath for unlisted classes", ex);
|
||||
}
|
||||
try {
|
||||
ClassLoader cl = this.resourcePatternResolver.getClassLoader();
|
||||
for (String className : entityClassNames) {
|
||||
addAnnotatedClass(cl.loadClass(className));
|
||||
}
|
||||
for (String className : converterClassNames) {
|
||||
addAttributeConverter((Class<? extends AttributeConverter<?, ?>>) cl.loadClass(className));
|
||||
}
|
||||
for (String packageName : packageNames) {
|
||||
addPackage(packageName);
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new MappingException("Failed to load annotated classes from classpath", ex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether any of the configured entity type filters matches
|
||||
* the current class descriptor contained in the metadata reader.
|
||||
*/
|
||||
private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
|
||||
if (this.entityTypeFilters != null) {
|
||||
for (TypeFilter filter : this.entityTypeFilters) {
|
||||
if (filter.match(reader, readerFactory)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Hibernate {@code SessionFactory} through background bootstrapping,
|
||||
* using the given executor for a parallel initialization phase
|
||||
* (e.g. a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}).
|
||||
* <p>{@code SessionFactory} initialization will then switch into background
|
||||
* bootstrap mode, with a {@code SessionFactory} proxy immediately returned for
|
||||
* injection purposes instead of waiting for Hibernate's bootstrapping to complete.
|
||||
* However, note that the first actual call to a {@code SessionFactory} method will
|
||||
* then block until Hibernate's bootstrapping completed, if not ready by then.
|
||||
* For maximum benefit, make sure to avoid early {@code SessionFactory} calls
|
||||
* in init methods of related beans, even for metadata introspection purposes.
|
||||
* @since 4.3
|
||||
* @see #buildSessionFactory()
|
||||
*/
|
||||
public SessionFactory buildSessionFactory(AsyncTaskExecutor bootstrapExecutor) {
|
||||
Assert.notNull(bootstrapExecutor, "AsyncTaskExecutor must not be null");
|
||||
return (SessionFactory) Proxy.newProxyInstance(this.resourcePatternResolver.getClassLoader(),
|
||||
new Class<?>[] {SessionFactoryImplementor.class, InfrastructureProxy.class},
|
||||
new BootstrapSessionFactoryInvocationHandler(bootstrapExecutor));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Proxy invocation handler for background bootstrapping, only enforcing
|
||||
* a fully initialized target {@code SessionFactory} when actually needed.
|
||||
* @since 4.3
|
||||
*/
|
||||
private class BootstrapSessionFactoryInvocationHandler implements InvocationHandler {
|
||||
|
||||
private final Future<SessionFactory> sessionFactoryFuture;
|
||||
|
||||
public BootstrapSessionFactoryInvocationHandler(AsyncTaskExecutor bootstrapExecutor) {
|
||||
this.sessionFactoryFuture = bootstrapExecutor.submit(new Callable<SessionFactory>() {
|
||||
@Override
|
||||
public SessionFactory call() throws Exception {
|
||||
return buildSessionFactory();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
try {
|
||||
if (method.getName().equals("equals")) {
|
||||
// Only consider equal when proxies are identical.
|
||||
return (proxy == args[0]);
|
||||
}
|
||||
else if (method.getName().equals("hashCode")) {
|
||||
// Use hashCode of EntityManagerFactory proxy.
|
||||
return System.identityHashCode(proxy);
|
||||
}
|
||||
else if (method.getName().equals("getProperties")) {
|
||||
return getProperties();
|
||||
}
|
||||
else if (method.getName().equals("getWrappedObject")) {
|
||||
// Call coming in through InfrastructureProxy interface...
|
||||
return getSessionFactory();
|
||||
}
|
||||
// Regular delegation to the target SessionFactory,
|
||||
// enforcing its full initialization...
|
||||
return method.invoke(getSessionFactory(), args);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
}
|
||||
|
||||
private SessionFactory getSessionFactory() {
|
||||
try {
|
||||
return this.sessionFactoryFuture.get();
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
throw new IllegalStateException("Interrupted during initialization of Hibernate SessionFactory: " +
|
||||
ex.getMessage());
|
||||
}
|
||||
catch (ExecutionException ex) {
|
||||
throw new IllegalStateException("Failed to asynchronously initialize Hibernate SessionFactory: " +
|
||||
ex.getMessage(), ex.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.hibernate5;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.NonUniqueObjectException;
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
import org.hibernate.ObjectDeletedException;
|
||||
import org.hibernate.PersistentObjectException;
|
||||
import org.hibernate.PessimisticLockException;
|
||||
import org.hibernate.PropertyValueException;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.QueryTimeoutException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.lock.OptimisticEntityLockException;
|
||||
import org.hibernate.dialect.lock.PessimisticEntityLockException;
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.exception.DataException;
|
||||
import org.hibernate.exception.JDBCConnectionException;
|
||||
import org.hibernate.exception.LockAcquisitionException;
|
||||
import org.hibernate.exception.SQLGrammarException;
|
||||
import org.hibernate.service.UnknownServiceException;
|
||||
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Helper class featuring methods for Hibernate Session handling.
|
||||
* Also provides support for exception translation.
|
||||
*
|
||||
* <p>Used internally by {@link HibernateTransactionManager}.
|
||||
* Can also be used directly in application code.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @see HibernateExceptionTranslator
|
||||
* @see HibernateTransactionManager
|
||||
*/
|
||||
public abstract class SessionFactoryUtils {
|
||||
|
||||
/**
|
||||
* Order value for TransactionSynchronization objects that clean up Hibernate Sessions.
|
||||
* Returns {@code DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100}
|
||||
* to execute Session cleanup before JDBC Connection cleanup, if any.
|
||||
* @see DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
|
||||
*/
|
||||
public static final int SESSION_SYNCHRONIZATION_ORDER =
|
||||
DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
|
||||
|
||||
static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
|
||||
|
||||
|
||||
private static Method getFlushMode;
|
||||
|
||||
static {
|
||||
try {
|
||||
// Hibernate 5.2+ getHibernateFlushMode()
|
||||
getFlushMode = Session.class.getMethod("getHibernateFlushMode");
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
try {
|
||||
// Hibernate 5.0/5.1 getFlushMode() with FlushMode return type
|
||||
getFlushMode = Session.class.getMethod("getFlushMode");
|
||||
}
|
||||
catch (NoSuchMethodException ex2) {
|
||||
throw new IllegalStateException("No compatible Hibernate getFlushMode signature found", ex2);
|
||||
}
|
||||
}
|
||||
// Check that it is the Hibernate FlushMode type, not JPA's...
|
||||
Assert.state(FlushMode.class == getFlushMode.getReturnType());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the native Hibernate FlushMode, adapting between Hibernate 5.0/5.1 and 5.2+.
|
||||
* @param session the Hibernate Session to get the flush mode from
|
||||
* @return the FlushMode (never {@code null})
|
||||
* @since 4.3
|
||||
*/
|
||||
static FlushMode getFlushMode(Session session) {
|
||||
return (FlushMode) ReflectionUtils.invokeMethod(getFlushMode, session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform actual closing of the Hibernate Session,
|
||||
* catching and logging any cleanup exceptions thrown.
|
||||
* @param session the Hibernate Session to close (may be {@code null})
|
||||
* @see Session#close()
|
||||
*/
|
||||
public static void closeSession(Session session) {
|
||||
if (session != null) {
|
||||
try {
|
||||
session.close();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
logger.debug("Could not close Hibernate Session", ex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Unexpected exception on closing Hibernate Session", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the DataSource of the given SessionFactory.
|
||||
* @param sessionFactory the SessionFactory to check
|
||||
* @return the DataSource, or {@code null} if none found
|
||||
* @see ConnectionProvider
|
||||
*/
|
||||
public static DataSource getDataSource(SessionFactory sessionFactory) {
|
||||
Method getProperties = ClassUtils.getMethodIfAvailable(sessionFactory.getClass(), "getProperties");
|
||||
if (getProperties != null) {
|
||||
Map<?, ?> props = (Map<?, ?>) ReflectionUtils.invokeMethod(getProperties, sessionFactory);
|
||||
Object dataSourceValue = props.get(Environment.DATASOURCE);
|
||||
if (dataSourceValue instanceof DataSource) {
|
||||
return (DataSource) dataSourceValue;
|
||||
}
|
||||
}
|
||||
if (sessionFactory instanceof SessionFactoryImplementor) {
|
||||
SessionFactoryImplementor sfi = (SessionFactoryImplementor) sessionFactory;
|
||||
try {
|
||||
ConnectionProvider cp = sfi.getServiceRegistry().getService(ConnectionProvider.class);
|
||||
if (cp != null) {
|
||||
return cp.unwrap(DataSource.class);
|
||||
}
|
||||
}
|
||||
catch (UnknownServiceException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No ConnectionProvider found - cannot determine DataSource for SessionFactory: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given HibernateException to an appropriate exception
|
||||
* from the {@code org.springframework.dao} hierarchy.
|
||||
* @param ex HibernateException that occurred
|
||||
* @return the corresponding DataAccessException instance
|
||||
* @see HibernateExceptionTranslator#convertHibernateAccessException
|
||||
* @see HibernateTransactionManager#convertHibernateAccessException
|
||||
*/
|
||||
public static DataAccessException convertHibernateAccessException(HibernateException ex) {
|
||||
if (ex instanceof JDBCConnectionException) {
|
||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof SQLGrammarException) {
|
||||
SQLGrammarException jdbcEx = (SQLGrammarException) ex;
|
||||
return new InvalidDataAccessResourceUsageException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof QueryTimeoutException) {
|
||||
QueryTimeoutException jdbcEx = (QueryTimeoutException) ex;
|
||||
return new org.springframework.dao.QueryTimeoutException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof LockAcquisitionException) {
|
||||
LockAcquisitionException jdbcEx = (LockAcquisitionException) ex;
|
||||
return new CannotAcquireLockException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof PessimisticLockException) {
|
||||
PessimisticLockException jdbcEx = (PessimisticLockException) ex;
|
||||
return new PessimisticLockingFailureException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof ConstraintViolationException) {
|
||||
ConstraintViolationException jdbcEx = (ConstraintViolationException) ex;
|
||||
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() +
|
||||
"]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
|
||||
}
|
||||
if (ex instanceof DataException) {
|
||||
DataException jdbcEx = (DataException) ex;
|
||||
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
|
||||
}
|
||||
if (ex instanceof JDBCException) {
|
||||
return new HibernateJdbcException((JDBCException) ex);
|
||||
}
|
||||
// end of JDBCException (subclass) handling
|
||||
|
||||
if (ex instanceof QueryException) {
|
||||
return new HibernateQueryException((QueryException) ex);
|
||||
}
|
||||
if (ex instanceof NonUniqueResultException) {
|
||||
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
|
||||
}
|
||||
if (ex instanceof NonUniqueObjectException) {
|
||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof PropertyValueException) {
|
||||
return new DataIntegrityViolationException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof PersistentObjectException) {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof TransientObjectException) {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof ObjectDeletedException) {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof UnresolvableObjectException) {
|
||||
return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex);
|
||||
}
|
||||
if (ex instanceof WrongClassException) {
|
||||
return new HibernateObjectRetrievalFailureException((WrongClassException) ex);
|
||||
}
|
||||
if (ex instanceof StaleObjectStateException) {
|
||||
return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex);
|
||||
}
|
||||
if (ex instanceof StaleStateException) {
|
||||
return new HibernateOptimisticLockingFailureException((StaleStateException) ex);
|
||||
}
|
||||
if (ex instanceof OptimisticEntityLockException) {
|
||||
return new HibernateOptimisticLockingFailureException((OptimisticEntityLockException) ex);
|
||||
}
|
||||
if (ex instanceof PessimisticEntityLockException) {
|
||||
if (ex.getCause() instanceof LockAcquisitionException) {
|
||||
return new CannotAcquireLockException(ex.getMessage(), ex.getCause());
|
||||
}
|
||||
return new PessimisticLockingFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
// fallback
|
||||
return new HibernateSystemException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.hibernate5;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
|
||||
import org.springframework.transaction.support.ResourceHolderSupport;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
|
||||
* HibernateTransactionManager binds instances of this class to the thread,
|
||||
* for a given SessionFactory.
|
||||
*
|
||||
* <p>Note: This is an SPI class, not intended to be used by applications.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @see HibernateTransactionManager
|
||||
* @see SessionFactoryUtils
|
||||
*/
|
||||
public class SessionHolder extends ResourceHolderSupport {
|
||||
|
||||
private Session session;
|
||||
|
||||
private Transaction transaction;
|
||||
|
||||
private FlushMode previousFlushMode;
|
||||
|
||||
|
||||
public SessionHolder(Session session) {
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
public void setTransaction(Transaction transaction) {
|
||||
this.transaction = transaction;
|
||||
}
|
||||
|
||||
public Transaction getTransaction() {
|
||||
return this.transaction;
|
||||
}
|
||||
|
||||
public void setPreviousFlushMode(FlushMode previousFlushMode) {
|
||||
this.previousFlushMode = previousFlushMode;
|
||||
}
|
||||
|
||||
public FlushMode getPreviousFlushMode() {
|
||||
return this.previousFlushMode;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
this.transaction = null;
|
||||
this.previousFlushMode = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.hibernate5;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
|
||||
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
|
||||
|
||||
/**
|
||||
* Simple synchronization adapter that propagates a {@code flush()} call
|
||||
* to the underlying Hibernate Session. Used in combination with JTA.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
*/
|
||||
public class SpringFlushSynchronization extends TransactionSynchronizationAdapter {
|
||||
|
||||
private final Session session;
|
||||
|
||||
|
||||
public SpringFlushSynchronization(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
try {
|
||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
|
||||
this.session.flush();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof SpringFlushSynchronization &&
|
||||
this.session == ((SpringFlushSynchronization) obj).session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.session.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.hibernate5;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.context.internal.JTASessionContext;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* Spring-specific subclass of Hibernate's JTASessionContext,
|
||||
* setting {@code FlushMode.MANUAL} for read-only transactions.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SpringJtaSessionContext extends JTASessionContext {
|
||||
|
||||
public SpringJtaSessionContext(SessionFactoryImplementor factory) {
|
||||
super(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Session buildOrObtainSession() {
|
||||
Session session = super.buildOrObtainSession();
|
||||
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.hibernate5;
|
||||
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.context.spi.CurrentSessionContext;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
|
||||
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* Implementation of Hibernate 3.1's CurrentSessionContext interface
|
||||
* that delegates to Spring's SessionFactoryUtils for providing a
|
||||
* Spring-managed current Session.
|
||||
*
|
||||
* <p>This CurrentSessionContext implementation can also be specified in custom
|
||||
* SessionFactory setup through the "hibernate.current_session_context_class"
|
||||
* property, with the fully qualified name of this class as value.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SpringSessionContext implements CurrentSessionContext {
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
private TransactionManager transactionManager;
|
||||
|
||||
private CurrentSessionContext jtaSessionContext;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SpringSessionContext for the given Hibernate SessionFactory.
|
||||
* @param sessionFactory the SessionFactory to provide current Sessions for
|
||||
*/
|
||||
public SpringSessionContext(SessionFactoryImplementor sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
try {
|
||||
JtaPlatform jtaPlatform = sessionFactory.getServiceRegistry().getService(JtaPlatform.class);
|
||||
this.transactionManager = jtaPlatform.retrieveTransactionManager();
|
||||
if (this.transactionManager != null) {
|
||||
this.jtaSessionContext = new SpringJtaSessionContext(sessionFactory);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LogFactory.getLog(SpringSessionContext.class).warn(
|
||||
"Could not introspect Hibernate JtaPlatform for SpringJtaSessionContext", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the Spring-managed Session for the current thread, if any.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public Session currentSession() throws HibernateException {
|
||||
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
|
||||
if (value instanceof Session) {
|
||||
return (Session) value;
|
||||
}
|
||||
else if (value instanceof SessionHolder) {
|
||||
SessionHolder sessionHolder = (SessionHolder) value;
|
||||
Session session = sessionHolder.getSession();
|
||||
if (!sessionHolder.isSynchronizedWithTransaction() &&
|
||||
TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
TransactionSynchronizationManager.registerSynchronization(
|
||||
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, false));
|
||||
sessionHolder.setSynchronizedWithTransaction(true);
|
||||
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
|
||||
// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
|
||||
FlushMode flushMode = SessionFactoryUtils.getFlushMode(session);
|
||||
if (flushMode.equals(FlushMode.MANUAL) &&
|
||||
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
||||
session.setFlushMode(FlushMode.AUTO);
|
||||
sessionHolder.setPreviousFlushMode(flushMode);
|
||||
}
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
if (this.transactionManager != null) {
|
||||
try {
|
||||
if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
|
||||
Session session = this.jtaSessionContext.currentSession();
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
TransactionSynchronizationManager.registerSynchronization(new SpringFlushSynchronization(session));
|
||||
}
|
||||
return session;
|
||||
}
|
||||
}
|
||||
catch (SystemException ex) {
|
||||
throw new HibernateException("JTA TransactionManager found but status check failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
Session session = this.sessionFactory.openSession();
|
||||
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
}
|
||||
SessionHolder sessionHolder = new SessionHolder(session);
|
||||
TransactionSynchronizationManager.registerSynchronization(
|
||||
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
|
||||
TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
|
||||
sessionHolder.setSynchronizedWithTransaction(true);
|
||||
return session;
|
||||
}
|
||||
else {
|
||||
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.hibernate5;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* Callback for resource cleanup at the end of a Spring-managed transaction
|
||||
* for a pre-bound Hibernate Session.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
*/
|
||||
public class SpringSessionSynchronization implements TransactionSynchronization, Ordered {
|
||||
|
||||
private final SessionHolder sessionHolder;
|
||||
|
||||
private final SessionFactory sessionFactory;
|
||||
|
||||
private final boolean newSession;
|
||||
|
||||
private boolean holderActive = true;
|
||||
|
||||
|
||||
public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory) {
|
||||
this(sessionHolder, sessionFactory, false);
|
||||
}
|
||||
|
||||
public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory, boolean newSession) {
|
||||
this.sessionHolder = sessionHolder;
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.newSession = newSession;
|
||||
}
|
||||
|
||||
|
||||
private Session getCurrentSession() {
|
||||
return this.sessionHolder.getSession();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suspend() {
|
||||
if (this.holderActive) {
|
||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
||||
// Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss.
|
||||
getCurrentSession().disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
if (this.holderActive) {
|
||||
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
try {
|
||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
|
||||
getCurrentSession().flush();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCommit(boolean readOnly) throws DataAccessException {
|
||||
if (!readOnly) {
|
||||
Session session = getCurrentSession();
|
||||
// Read-write transaction -> flush the Hibernate Session.
|
||||
// Further check: only flush when not FlushMode.MANUAL.
|
||||
if (!FlushMode.MANUAL.equals(SessionFactoryUtils.getFlushMode(session))) {
|
||||
try {
|
||||
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization");
|
||||
session.flush();
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw SessionFactoryUtils.convertHibernateAccessException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void beforeCompletion() {
|
||||
try {
|
||||
Session session = this.sessionHolder.getSession();
|
||||
if (this.sessionHolder.getPreviousFlushMode() != null) {
|
||||
// In case of pre-bound Session, restore previous flush mode.
|
||||
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
|
||||
}
|
||||
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
|
||||
session.disconnect();
|
||||
}
|
||||
finally {
|
||||
// Unbind at this point if it's a new Session...
|
||||
if (this.newSession) {
|
||||
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
|
||||
this.holderActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
try {
|
||||
if (status != STATUS_COMMITTED) {
|
||||
// Clear all pending inserts/updates/deletes in the Session.
|
||||
// Necessary for pre-bound Sessions, to avoid inconsistent state.
|
||||
this.sessionHolder.getSession().clear();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.sessionHolder.setSynchronizedWithTransaction(false);
|
||||
// Call close() at this point if it's a new Session...
|
||||
if (this.newSession) {
|
||||
SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Package providing integration of
|
||||
* <a href="http://www.hibernate.org">Hibernate 5.x</a>
|
||||
* with Spring concepts.
|
||||
*
|
||||
* <p>Contains an implementation of Spring's transaction SPI for local Hibernate transactions.
|
||||
* This package is intentionally rather minimal, with no template classes or the like,
|
||||
* in order to follow Hibernate recommendations as closely as possible. We recommend
|
||||
* using Hibernate's native <code>sessionFactory.getCurrentSession()</code> style.
|
||||
*
|
||||
* <p><b>This package supports Hibernate 5.x only.</b>
|
||||
*/
|
||||
package org.springframework.orm.hibernate5;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3.support;
|
||||
package org.springframework.orm.hibernate5.support;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -22,6 +22,8 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.orm.hibernate5.SessionFactoryUtils;
|
||||
import org.springframework.orm.hibernate5.SessionHolder;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
|
||||
@@ -37,22 +39,20 @@ import org.springframework.web.context.request.async.DeferredResultProcessingInt
|
||||
* 2) The session is closed if an async request times out
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2.5
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
* @since 4.2
|
||||
*/
|
||||
@Deprecated
|
||||
class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter implements DeferredResultProcessingInterceptor {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AsyncRequestInterceptor.class);
|
||||
|
||||
private final SessionFactory sessionFactory;
|
||||
|
||||
private final org.springframework.orm.hibernate3.SessionHolder sessionHolder;
|
||||
private final SessionHolder sessionHolder;
|
||||
|
||||
private volatile boolean timeoutInProgress;
|
||||
|
||||
|
||||
public AsyncRequestInterceptor(SessionFactory sessionFactory, org.springframework.orm.hibernate3.SessionHolder sessionHolder) {
|
||||
public AsyncRequestInterceptor(SessionFactory sessionFactory, SessionHolder sessionHolder) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.sessionHolder = sessionHolder;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter imple
|
||||
private void closeAfterTimeout() {
|
||||
if (this.timeoutInProgress) {
|
||||
logger.debug("Closing Hibernate Session after async request timeout");
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
|
||||
SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.hibernate5.support;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.support.DaoSupport;
|
||||
import org.springframework.orm.hibernate5.HibernateTemplate;
|
||||
|
||||
/**
|
||||
* Convenient super class for Hibernate-based data access objects.
|
||||
*
|
||||
* <p>Requires a {@link SessionFactory} to be set, providing a
|
||||
* {@link org.springframework.orm.hibernate5.HibernateTemplate} based on it to
|
||||
* subclasses through the {@link #getHibernateTemplate()} method.
|
||||
* Can alternatively be initialized directly with a HibernateTemplate,
|
||||
* in order to reuse the latter's settings such as the SessionFactory,
|
||||
* exception translator, flush mode, etc.
|
||||
*
|
||||
* <p>This class will create its own HibernateTemplate instance if a SessionFactory
|
||||
* is passed in. The "allowCreate" flag on that HibernateTemplate will be "true"
|
||||
* by default. A custom HibernateTemplate instance can be used through overriding
|
||||
* {@link #createHibernateTemplate}.
|
||||
*
|
||||
* <p><b>NOTE: Hibernate access code can also be coded in plain Hibernate style.
|
||||
* Hence, for newly started projects, consider adopting the standard Hibernate
|
||||
* style of coding data access objects instead, based on
|
||||
* {@link SessionFactory#getCurrentSession()}.
|
||||
* This HibernateTemplate primarily exists as a migration helper for Hibernate 3
|
||||
* based data access code, to benefit from bug fixes in Hibernate 5.x.</b>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @see #setSessionFactory
|
||||
* @see #getHibernateTemplate
|
||||
* @see org.springframework.orm.hibernate5.HibernateTemplate
|
||||
*/
|
||||
public abstract class HibernateDaoSupport extends DaoSupport {
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* Set the Hibernate SessionFactory to be used by this DAO.
|
||||
* Will automatically create a HibernateTemplate for the given SessionFactory.
|
||||
* @see #createHibernateTemplate
|
||||
* @see #setHibernateTemplate
|
||||
*/
|
||||
public final void setSessionFactory(SessionFactory sessionFactory) {
|
||||
if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
|
||||
this.hibernateTemplate = createHibernateTemplate(sessionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HibernateTemplate for the given SessionFactory.
|
||||
* Only invoked if populating the DAO with a SessionFactory reference!
|
||||
* <p>Can be overridden in subclasses to provide a HibernateTemplate instance
|
||||
* with different configuration, or a custom HibernateTemplate subclass.
|
||||
* @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for
|
||||
* @return the new HibernateTemplate instance
|
||||
* @see #setSessionFactory
|
||||
*/
|
||||
protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
|
||||
return new HibernateTemplate(sessionFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Hibernate SessionFactory used by this DAO.
|
||||
*/
|
||||
public final SessionFactory getSessionFactory() {
|
||||
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HibernateTemplate for this DAO explicitly,
|
||||
* as an alternative to specifying a SessionFactory.
|
||||
* @see #setSessionFactory
|
||||
*/
|
||||
public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
|
||||
this.hibernateTemplate = hibernateTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HibernateTemplate for this DAO,
|
||||
* pre-initialized with the SessionFactory or set explicitly.
|
||||
* <p><b>Note: The returned HibernateTemplate is a shared instance.</b>
|
||||
* You may introspect its configuration, but not modify the configuration
|
||||
* (other than from within an {@link #initDao} implementation).
|
||||
* Consider creating a custom HibernateTemplate instance via
|
||||
* {@code new HibernateTemplate(getSessionFactory())}, in which case
|
||||
* you're allowed to customize the settings on the resulting instance.
|
||||
*/
|
||||
public final HibernateTemplate getHibernateTemplate() {
|
||||
return this.hibernateTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void checkDaoConfig() {
|
||||
if (this.hibernateTemplate == null) {
|
||||
throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Conveniently obtain the current Hibernate Session.
|
||||
* @return the Hibernate Session
|
||||
* @throws DataAccessResourceFailureException if the Session couldn't be created
|
||||
* @see SessionFactory#getCurrentSession()
|
||||
*/
|
||||
protected final Session currentSession() throws DataAccessResourceFailureException {
|
||||
return getSessionFactory().getCurrentSession();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.hibernate5.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.orm.hibernate5.SessionFactoryUtils;
|
||||
import org.springframework.orm.hibernate5.SessionHolder;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
/**
|
||||
* Servlet Filter that binds a Hibernate Session to the thread for the entire
|
||||
* processing of the request. Intended for the "Open Session in View" pattern,
|
||||
* i.e. to allow for lazy loading in web views despite the original transactions
|
||||
* already being completed.
|
||||
*
|
||||
* <p>This filter makes Hibernate Sessions available via the current thread, which
|
||||
* will be autodetected by transaction managers. It is suitable for service layer
|
||||
* transactions via {@link org.springframework.orm.hibernate5.HibernateTransactionManager}
|
||||
* as well as for non-transactional execution (if configured appropriately).
|
||||
*
|
||||
* <p><b>NOTE</b>: This filter will by default <i>not</i> flush the Hibernate Session,
|
||||
* with the flush mode set to {@code FlushMode.NEVER}. It assumes to be used
|
||||
* in combination with service layer transactions that care for the flushing: The
|
||||
* active transaction manager will temporarily change the flush mode to
|
||||
* {@code FlushMode.AUTO} during a read-write transaction, with the flush
|
||||
* mode reset to {@code FlushMode.NEVER} at the end of each transaction.
|
||||
*
|
||||
* <p><b>WARNING:</b> Applying this filter to existing logic can cause issues that
|
||||
* have not appeared before, through the use of a single Hibernate Session for the
|
||||
* processing of an entire request. In particular, the reassociation of persistent
|
||||
* objects with a Hibernate Session has to occur at the very beginning of request
|
||||
* processing, to avoid clashes with already loaded instances of the same objects.
|
||||
*
|
||||
* <p>Looks up the SessionFactory in Spring's root web application context.
|
||||
* Supports a "sessionFactoryBeanName" filter init-param in {@code web.xml};
|
||||
* the default bean name is "sessionFactory".
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @see #lookupSessionFactory
|
||||
* @see OpenSessionInViewInterceptor
|
||||
* @see OpenSessionInterceptor
|
||||
* @see org.springframework.orm.hibernate5.HibernateTransactionManager
|
||||
* @see TransactionSynchronizationManager
|
||||
* @see SessionFactory#getCurrentSession()
|
||||
*/
|
||||
public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||
|
||||
public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
|
||||
|
||||
private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
|
||||
|
||||
|
||||
/**
|
||||
* Set the bean name of the SessionFactory to fetch from Spring's
|
||||
* root application context. Default is "sessionFactory".
|
||||
* @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
|
||||
*/
|
||||
public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
|
||||
this.sessionFactoryBeanName = sessionFactoryBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean name of the SessionFactory to fetch from Spring's
|
||||
* root application context.
|
||||
*/
|
||||
protected String getSessionFactoryBeanName() {
|
||||
return this.sessionFactoryBeanName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns "false" so that the filter may re-bind the opened Hibernate
|
||||
* {@code Session} to each asynchronously dispatched thread and postpone
|
||||
* closing it until the very last asynchronous dispatch.
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldNotFilterAsyncDispatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns "false" so that the filter may provide a Hibernate
|
||||
* {@code Session} to each error dispatches.
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldNotFilterErrorDispatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
SessionFactory sessionFactory = lookupSessionFactory(request);
|
||||
boolean participate = false;
|
||||
|
||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
||||
String key = getAlreadyFilteredAttributeName();
|
||||
|
||||
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
|
||||
// Do not modify the Session: just set the participate flag.
|
||||
participate = true;
|
||||
}
|
||||
else {
|
||||
boolean isFirstRequest = !isAsyncDispatch(request);
|
||||
if (isFirstRequest || !applySessionBindingInterceptor(asyncManager, key)) {
|
||||
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
|
||||
Session session = openSession(sessionFactory);
|
||||
SessionHolder sessionHolder = new SessionHolder(session);
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||
|
||||
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
|
||||
asyncManager.registerCallableInterceptor(key, interceptor);
|
||||
asyncManager.registerDeferredResultInterceptor(key, interceptor);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
finally {
|
||||
if (!participate) {
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||
if (!isAsyncStarted(request)) {
|
||||
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
|
||||
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the SessionFactory that this filter should use,
|
||||
* taking the current HTTP request as argument.
|
||||
* <p>The default implementation delegates to the {@link #lookupSessionFactory()}
|
||||
* variant without arguments.
|
||||
* @param request the current request
|
||||
* @return the SessionFactory to use
|
||||
*/
|
||||
protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
|
||||
return lookupSessionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the SessionFactory that this filter should use.
|
||||
* <p>The default implementation looks for a bean with the specified name
|
||||
* in Spring's root application context.
|
||||
* @return the SessionFactory to use
|
||||
* @see #getSessionFactoryBeanName
|
||||
*/
|
||||
protected SessionFactory lookupSessionFactory() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
|
||||
}
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
|
||||
return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a Session for the SessionFactory that this filter uses.
|
||||
* <p>The default implementation delegates to the {@link SessionFactory#openSession}
|
||||
* method and sets the {@link Session}'s flush mode to "MANUAL".
|
||||
* @param sessionFactory the SessionFactory that this filter uses
|
||||
* @return the Session to use
|
||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
||||
* @see FlushMode#MANUAL
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
|
||||
try {
|
||||
Session session = sessionFactory.openSession();
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
return session;
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
|
||||
if (asyncManager.getCallableInterceptor(key) == null) {
|
||||
return false;
|
||||
}
|
||||
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.hibernate5.support;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.orm.hibernate5.SessionFactoryUtils;
|
||||
import org.springframework.orm.hibernate5.SessionHolder;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
|
||||
/**
|
||||
* Spring web request interceptor that binds a Hibernate {@code Session} to the
|
||||
* thread for the entire processing of the request.
|
||||
*
|
||||
* <p>This class is a concrete expression of the "Open Session in View" pattern, which
|
||||
* is a pattern that allows for the lazy loading of associations in web views despite
|
||||
* the original transactions already being completed.
|
||||
*
|
||||
* <p>This interceptor makes Hibernate Sessions available via the current thread,
|
||||
* which will be autodetected by transaction managers. It is suitable for service layer
|
||||
* transactions via {@link org.springframework.orm.hibernate5.HibernateTransactionManager}
|
||||
* as well as for non-transactional execution (if configured appropriately).
|
||||
*
|
||||
* <p>In contrast to {@link OpenSessionInViewFilter}, this interceptor is configured
|
||||
* in a Spring application context and can thus take advantage of bean wiring.
|
||||
*
|
||||
* <p><b>WARNING:</b> Applying this interceptor to existing logic can cause issues
|
||||
* that have not appeared before, through the use of a single Hibernate
|
||||
* {@code Session} for the processing of an entire request. In particular, the
|
||||
* reassociation of persistent objects with a Hibernate {@code Session} has to
|
||||
* occur at the very beginning of request processing, to avoid clashes with already
|
||||
* loaded instances of the same objects.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @see OpenSessionInViewFilter
|
||||
* @see OpenSessionInterceptor
|
||||
* @see org.springframework.orm.hibernate5.HibernateTransactionManager
|
||||
* @see TransactionSynchronizationManager
|
||||
* @see SessionFactory#getCurrentSession()
|
||||
*/
|
||||
public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor {
|
||||
|
||||
/**
|
||||
* Suffix that gets appended to the {@code SessionFactory}
|
||||
* {@code toString()} representation for the "participate in existing
|
||||
* session handling" request attribute.
|
||||
* @see #getParticipateAttributeName
|
||||
*/
|
||||
public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Set the Hibernate SessionFactory that should be used to create Hibernate Sessions.
|
||||
*/
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Hibernate SessionFactory that should be used to create Hibernate Sessions.
|
||||
*/
|
||||
public SessionFactory getSessionFactory() {
|
||||
return this.sessionFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open a new Hibernate {@code Session} according and bind it to the thread via the
|
||||
* {@link TransactionSynchronizationManager}.
|
||||
*/
|
||||
@Override
|
||||
public void preHandle(WebRequest request) throws DataAccessException {
|
||||
String participateAttributeName = getParticipateAttributeName();
|
||||
|
||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
||||
if (asyncManager.hasConcurrentResult()) {
|
||||
if (applySessionBindingInterceptor(asyncManager, participateAttributeName)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
|
||||
// Do not modify the Session: just mark the request accordingly.
|
||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
||||
int newCount = (count != null ? count + 1 : 1);
|
||||
request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST);
|
||||
}
|
||||
else {
|
||||
logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor");
|
||||
Session session = openSession();
|
||||
SessionHolder sessionHolder = new SessionHolder(session);
|
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||
|
||||
AsyncRequestInterceptor asyncRequestInterceptor =
|
||||
new AsyncRequestInterceptor(getSessionFactory(), sessionHolder);
|
||||
asyncManager.registerCallableInterceptor(participateAttributeName, asyncRequestInterceptor);
|
||||
asyncManager.registerDeferredResultInterceptor(participateAttributeName, asyncRequestInterceptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(WebRequest request, ModelMap model) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind the Hibernate {@code Session} from the thread and close it).
|
||||
* @see TransactionSynchronizationManager
|
||||
*/
|
||||
@Override
|
||||
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
|
||||
if (!decrementParticipateCount(request)) {
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
||||
logger.debug("Closing Hibernate Session in OpenSessionInViewInterceptor");
|
||||
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean decrementParticipateCount(WebRequest request) {
|
||||
String participateAttributeName = getParticipateAttributeName();
|
||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
||||
if (count == null) {
|
||||
return false;
|
||||
}
|
||||
// Do not modify the Session: just clear the marker.
|
||||
if (count > 1) {
|
||||
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST);
|
||||
}
|
||||
else {
|
||||
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConcurrentHandlingStarted(WebRequest request) {
|
||||
if (!decrementParticipateCount(request)) {
|
||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a Session for the SessionFactory that this interceptor uses.
|
||||
* <p>The default implementation delegates to the {@link SessionFactory#openSession}
|
||||
* method and sets the {@link Session}'s flush mode to "MANUAL".
|
||||
* @return the Session to use
|
||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
||||
* @see FlushMode#MANUAL
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Session openSession() throws DataAccessResourceFailureException {
|
||||
try {
|
||||
Session session = getSessionFactory().openSession();
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
return session;
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the request attribute that identifies that a request is
|
||||
* already intercepted.
|
||||
* <p>The default implementation takes the {@code toString()} representation
|
||||
* of the {@code SessionFactory} instance and appends {@link #PARTICIPATE_SUFFIX}.
|
||||
*/
|
||||
protected String getParticipateAttributeName() {
|
||||
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
|
||||
}
|
||||
|
||||
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
|
||||
if (asyncManager.getCallableInterceptor(key) == null) {
|
||||
return false;
|
||||
}
|
||||
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.orm.hibernate3.support;
|
||||
package org.springframework.orm.hibernate5.support;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
@@ -25,6 +25,8 @@ import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.orm.hibernate5.SessionFactoryUtils;
|
||||
import org.springframework.orm.hibernate5.SessionHolder;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
@@ -36,20 +38,14 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* MVC setup. It opens a new {@link Session} with flush mode "MANUAL" since the
|
||||
* Session is only meant for reading, except when participating in a transaction.
|
||||
*
|
||||
* <p>Note: This can serve as a streamlined alternative to the outdated
|
||||
* {@link org.springframework.orm.hibernate3.HibernateInterceptor}, providing
|
||||
* plain Session binding without any automatic exception translation or the like.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0.2
|
||||
* @since 4.2
|
||||
* @see OpenSessionInViewInterceptor
|
||||
* @see OpenSessionInViewFilter
|
||||
* @see org.springframework.orm.hibernate3.HibernateTransactionManager
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
* @see org.hibernate.SessionFactory#getCurrentSession()
|
||||
* @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
|
||||
* @see org.springframework.orm.hibernate5.HibernateTransactionManager
|
||||
* @see TransactionSynchronizationManager
|
||||
* @see SessionFactory#getCurrentSession()
|
||||
*/
|
||||
@Deprecated
|
||||
public class OpenSessionInterceptor implements MethodInterceptor, InitializingBean {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
@@ -84,11 +80,11 @@ public class OpenSessionInterceptor implements MethodInterceptor, InitializingBe
|
||||
// New Session to be bound for the current method's scope...
|
||||
Session session = openSession();
|
||||
try {
|
||||
TransactionSynchronizationManager.bindResource(sf, new org.springframework.orm.hibernate3.SessionHolder(session));
|
||||
TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
|
||||
return invocation.proceed();
|
||||
}
|
||||
finally {
|
||||
org.springframework.orm.hibernate3.SessionFactoryUtils.closeSession(session);
|
||||
SessionFactoryUtils.closeSession(session);
|
||||
TransactionSynchronizationManager.unbindResource(sf);
|
||||
}
|
||||
}
|
||||
@@ -104,8 +100,9 @@ public class OpenSessionInterceptor implements MethodInterceptor, InitializingBe
|
||||
* method and sets the {@link Session}'s flush mode to "MANUAL".
|
||||
* @return the Session to use
|
||||
* @throws DataAccessResourceFailureException if the Session could not be created
|
||||
* @see org.hibernate.FlushMode#MANUAL
|
||||
* @see FlushMode#MANUAL
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Session openSession() throws DataAccessResourceFailureException {
|
||||
try {
|
||||
Session session = getSessionFactory().openSession();
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Classes supporting the {@code org.springframework.orm.hibernate5} package.
|
||||
*/
|
||||
package org.springframework.orm.hibernate5.support;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -30,6 +30,7 @@ import javax.persistence.PersistenceException;
|
||||
import javax.persistence.PessimisticLockException;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.QueryTimeoutException;
|
||||
import javax.persistence.SynchronizationType;
|
||||
import javax.persistence.TransactionRequiredException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -81,26 +82,6 @@ public abstract class EntityManagerFactoryUtils {
|
||||
private static final Log logger = LogFactory.getLog(EntityManagerFactoryUtils.class);
|
||||
|
||||
|
||||
private static Method createEntityManagerWithSynchronizationTypeMethod;
|
||||
|
||||
private static Object synchronizationTypeUnsynchronized;
|
||||
|
||||
static {
|
||||
try {
|
||||
@SuppressWarnings( "rawtypes" )
|
||||
Class<Enum> synchronizationTypeClass = (Class<Enum>) ClassUtils.forName(
|
||||
"javax.persistence.SynchronizationType", EntityManagerFactoryUtils.class.getClassLoader());
|
||||
createEntityManagerWithSynchronizationTypeMethod = EntityManagerFactory.class.getMethod(
|
||||
"createEntityManager", synchronizationTypeClass, Map.class);
|
||||
synchronizationTypeUnsynchronized = Enum.valueOf(synchronizationTypeClass, "UNSYNCHRONIZED");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// No JPA 2.1 API available
|
||||
createEntityManagerWithSynchronizationTypeMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find an EntityManagerFactory with the given name in the given
|
||||
* Spring application context (represented as ListableBeanFactory).
|
||||
@@ -271,10 +252,9 @@ public abstract class EntityManagerFactoryUtils {
|
||||
// Create a new EntityManager for use within the current transaction.
|
||||
logger.debug("Opening JPA EntityManager");
|
||||
EntityManager em = null;
|
||||
if (!synchronizedWithTransaction && createEntityManagerWithSynchronizationTypeMethod != null) {
|
||||
if (!synchronizedWithTransaction) {
|
||||
try {
|
||||
em = (EntityManager) ReflectionUtils.invokeMethod(createEntityManagerWithSynchronizationTypeMethod,
|
||||
emf, synchronizationTypeUnsynchronized, properties);
|
||||
em = emf.createEntityManager(SynchronizationType.UNSYNCHRONIZED, properties);
|
||||
}
|
||||
catch (AbstractMethodError err) {
|
||||
// JPA 2.1 API available but method not actually implemented in persistence provider:
|
||||
|
||||
@@ -115,11 +115,11 @@ public abstract class SharedEntityManagerCreator {
|
||||
*/
|
||||
public static EntityManager createSharedEntityManager(
|
||||
EntityManagerFactory emf, Map<?, ?> properties, boolean synchronizedWithTransaction) {
|
||||
Class<?> entityManagerInterface = (emf instanceof EntityManagerFactoryInfo ?
|
||||
|
||||
Class<?> emIfc = (emf instanceof EntityManagerFactoryInfo ?
|
||||
((EntityManagerFactoryInfo) emf).getEntityManagerInterface() : EntityManager.class);
|
||||
return createSharedEntityManager(emf, properties, synchronizedWithTransaction,
|
||||
(entityManagerInterface == null ? NO_ENTITY_MANAGER_INTERFACES :
|
||||
new Class<?>[] { entityManagerInterface }));
|
||||
(emIfc == null ? NO_ENTITY_MANAGER_INTERFACES : new Class<?>[] {emIfc}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.orm.jpa.persistenceunit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -26,6 +25,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Converter;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
@@ -73,8 +73,7 @@ import org.springframework.util.ResourceUtils;
|
||||
* DataSource names are by default interpreted as JNDI names, and no load time weaving
|
||||
* is available (which requires weaving to be turned off in the persistence provider).
|
||||
*
|
||||
* <p><b>NOTE: Spring's JPA support requires JPA 2.0 or higher, as of Spring 4.0.</b>
|
||||
* Spring's persistence unit bootstrapping automatically detects JPA 2.1 at runtime.
|
||||
* <p><b>NOTE: Spring's JPA support requires JPA 2.1 or higher, as of Spring 5.0.</b>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
@@ -116,15 +115,7 @@ public class DefaultPersistenceUnitManager
|
||||
entityTypeFilters.add(new AnnotationTypeFilter(Entity.class, false));
|
||||
entityTypeFilters.add(new AnnotationTypeFilter(Embeddable.class, false));
|
||||
entityTypeFilters.add(new AnnotationTypeFilter(MappedSuperclass.class, false));
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> converterAnnotation = (Class<? extends Annotation>)
|
||||
ClassUtils.forName("javax.persistence.Converter", DefaultPersistenceUnitManager.class.getClassLoader());
|
||||
entityTypeFilters.add(new AnnotationTypeFilter(converterAnnotation, false));
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// JPA 2.1 API not available
|
||||
}
|
||||
entityTypeFilters.add(new AnnotationTypeFilter(Converter.class, false));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -33,6 +33,7 @@ import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
import javax.persistence.PersistenceProperty;
|
||||
import javax.persistence.PersistenceUnit;
|
||||
import javax.persistence.SynchronizationType;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -168,11 +169,6 @@ public class PersistenceAnnotationBeanPostProcessor
|
||||
implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor,
|
||||
MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware, Serializable {
|
||||
|
||||
/* Check JPA 2.1 PersistenceContext.synchronization() attribute */
|
||||
private static final Method synchronizationAttribute =
|
||||
ClassUtils.getMethodIfAvailable(PersistenceContext.class, "synchronization");
|
||||
|
||||
|
||||
private Object jndiEnvironment;
|
||||
|
||||
private boolean resourceRef = true;
|
||||
@@ -662,8 +658,7 @@ public class PersistenceAnnotationBeanPostProcessor
|
||||
}
|
||||
this.unitName = pc.unitName();
|
||||
this.type = pc.type();
|
||||
this.synchronizedWithTransaction = (synchronizationAttribute == null ||
|
||||
"SYNCHRONIZED".equals(ReflectionUtils.invokeMethod(synchronizationAttribute, pc).toString()));
|
||||
this.synchronizedWithTransaction = SynchronizationType.SYNCHRONIZED.equals(pc.synchronization());
|
||||
this.properties = properties;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.hibernate.HibernateException;
|
||||
import org.hibernate.NonUniqueObjectException;
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
import org.hibernate.ObjectDeletedException;
|
||||
import org.hibernate.OptimisticLockException;
|
||||
import org.hibernate.PersistentObjectException;
|
||||
import org.hibernate.PessimisticLockException;
|
||||
import org.hibernate.PropertyValueException;
|
||||
@@ -40,6 +39,8 @@ import org.hibernate.StaleStateException;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.dialect.lock.OptimisticEntityLockException;
|
||||
import org.hibernate.dialect.lock.PessimisticEntityLockException;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.exception.DataException;
|
||||
import org.hibernate.exception.JDBCConnectionException;
|
||||
@@ -57,7 +58,6 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.jdbc.datasource.ConnectionHandle;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.orm.ObjectOptimisticLockingFailureException;
|
||||
import org.springframework.orm.ObjectRetrievalFailureException;
|
||||
import org.springframework.orm.jpa.DefaultJpaDialect;
|
||||
@@ -67,13 +67,11 @@ import org.springframework.transaction.InvalidIsolationLevelException;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.orm.jpa.JpaDialect} implementation for
|
||||
* Hibernate EntityManager. Developed and tested against Hibernate 3.6,
|
||||
* 4.2/4.3 as well as 5.0/5.1/5.2.
|
||||
* Hibernate EntityManager. Developed against Hibernate 5.0/5.1/5.2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Costin Leau
|
||||
@@ -85,29 +83,9 @@ import org.springframework.util.ReflectionUtils;
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
|
||||
private static Class<?> optimisticLockExceptionClass;
|
||||
|
||||
private static Class<?> pessimisticLockExceptionClass;
|
||||
|
||||
private static Method getFlushMode;
|
||||
|
||||
static {
|
||||
// Checking for Hibernate 4.x's Optimistic/PessimisticEntityLockException
|
||||
ClassLoader cl = HibernateJpaDialect.class.getClassLoader();
|
||||
try {
|
||||
optimisticLockExceptionClass = cl.loadClass("org.hibernate.dialect.lock.OptimisticEntityLockException");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// OptimisticLockException is deprecated on Hibernate 4.x; we're just using it on 3.x anyway
|
||||
optimisticLockExceptionClass = OptimisticLockException.class;
|
||||
}
|
||||
try {
|
||||
pessimisticLockExceptionClass = cl.loadClass("org.hibernate.dialect.lock.PessimisticEntityLockException");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
pessimisticLockExceptionClass = null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Hibernate 5.2+ getHibernateFlushMode()
|
||||
getFlushMode = Session.class.getMethod("getHibernateFlushMode");
|
||||
@@ -126,7 +104,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
}
|
||||
|
||||
|
||||
boolean prepareConnection = (HibernateConnectionHandle.sessionConnectionMethod == null);
|
||||
boolean prepareConnection = true;
|
||||
|
||||
|
||||
/**
|
||||
@@ -135,9 +113,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
* isolation level and/or the transaction's read-only flag to the underlying
|
||||
* JDBC Connection.
|
||||
* <p>Default is "true" on Hibernate EntityManager 4.x (with its 'on-close'
|
||||
* connection release mode, and "false" on Hibernate EntityManager 3.6 (due to
|
||||
* the 'after-transaction' release mode there). <b>Note that Hibernate 4.2+ is
|
||||
* strongly recommended in order to make isolation levels work efficiently.</b>
|
||||
* connection release mode.
|
||||
* <p>If you turn this flag off, JPA transaction management will not support
|
||||
* per-transaction isolation levels anymore. It will not call
|
||||
* {@code Connection.setReadOnly(true)} for read-only transactions anymore either.
|
||||
@@ -179,9 +155,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
}
|
||||
else if (isolationLevelNeeded) {
|
||||
throw new InvalidIsolationLevelException(getClass().getSimpleName() +
|
||||
" does not support custom isolation levels since the 'prepareConnection' flag is off. " +
|
||||
"This is the case on Hibernate 3.6 by default; either switch that flag at your own risk " +
|
||||
"or upgrade to Hibernate 4.x, with 4.2+ recommended.");
|
||||
" does not support custom isolation levels since the 'prepareConnection' flag is off.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,10 +293,10 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
if (ex instanceof StaleStateException) {
|
||||
return new ObjectOptimisticLockingFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
if (optimisticLockExceptionClass.isInstance(ex)) {
|
||||
if (ex instanceof OptimisticEntityLockException) {
|
||||
return new ObjectOptimisticLockingFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
if (pessimisticLockExceptionClass != null && pessimisticLockExceptionClass.isInstance(ex)) {
|
||||
if (ex instanceof PessimisticEntityLockException) {
|
||||
if (ex.getCause() instanceof LockAcquisitionException) {
|
||||
return new CannotAcquireLockException(ex.getMessage(), ex.getCause());
|
||||
}
|
||||
@@ -376,11 +350,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
|
||||
private static class HibernateConnectionHandle implements ConnectionHandle {
|
||||
|
||||
// This will find a corresponding method on Hibernate 3.x but not on 4.x
|
||||
private static final Method sessionConnectionMethod =
|
||||
ClassUtils.getMethodIfAvailable(Session.class, "connection");
|
||||
|
||||
private static volatile Method connectionMethodToUse = sessionConnectionMethod;
|
||||
private static volatile Method connectionMethodToUse;
|
||||
|
||||
private final Session session;
|
||||
|
||||
@@ -395,20 +365,12 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
|
||||
@Override
|
||||
public void releaseConnection(Connection con) {
|
||||
if (sessionConnectionMethod != null) {
|
||||
// Need to explicitly call close() with Hibernate 3.x in order to allow
|
||||
// for eager release of the underlying physical Connection if necessary.
|
||||
// However, do not do this on Hibernate 4.2+ since it would return the
|
||||
// physical Connection to the pool right away, making it unusable for
|
||||
// further operations within the current transaction!
|
||||
JdbcUtils.closeConnection(con);
|
||||
}
|
||||
}
|
||||
|
||||
public static Connection doGetConnection(Session session) {
|
||||
try {
|
||||
if (connectionMethodToUse == null) {
|
||||
// Reflective lookup to find SessionImpl's connection() method on Hibernate 4.x
|
||||
// Reflective lookup to find SessionImpl's connection() method on Hibernate 4.x/5.x
|
||||
connectionMethodToUse = session.getClass().getMethod("connection");
|
||||
}
|
||||
return (Connection) ReflectionUtils.invokeMethod(connectionMethodToUse, session);
|
||||
|
||||
@@ -32,11 +32,13 @@ import org.hibernate.dialect.MySQLDialect;
|
||||
import org.hibernate.dialect.Oracle9iDialect;
|
||||
import org.hibernate.dialect.PostgreSQLDialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.jpa.HibernateEntityManager;
|
||||
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate
|
||||
* EntityManager. Developed and tested against Hibernate 3.6, 4.2/4.3 as well as 5.x.
|
||||
* <b>Hibernate 4.2+ is strongly recommended for use with Spring 4.0+.</b>
|
||||
* EntityManager. Developed and tested against Hibernate 5.0, 5.1 and 5.2;
|
||||
* backwards-compatible with Hibernate 4.3 as well.
|
||||
*
|
||||
* <p>Exposes Hibernate's persistence provider and EntityManager extension interface,
|
||||
* and adapts {@link AbstractJpaVendorAdapter}'s common configuration settings.
|
||||
@@ -46,18 +48,10 @@ import org.hibernate.dialect.SQLServerDialect;
|
||||
* along with Spring-driven entity scanning which requires no {@code persistence.xml}
|
||||
* ({@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPackagesToScan}).
|
||||
*
|
||||
* <p>Note that the package location of Hibernate's JPA support changed from 4.2 to 4.3:
|
||||
* from {@code org.hibernate.ejb.HibernateEntityManager(Factory)} to
|
||||
* {@code org.hibernate.jpa.HibernateEntityManager(Factory)}. As of Spring 4.0,
|
||||
* we're exposing the correct, non-deprecated variant depending on the Hibernate
|
||||
* version encountered at runtime, in order to avoid deprecation log entries.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
* @see HibernateJpaDialect
|
||||
* @see org.hibernate.ejb.HibernatePersistence
|
||||
* @see org.hibernate.ejb.HibernateEntityManager
|
||||
*/
|
||||
public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
|
||||
|
||||
@@ -73,31 +67,9 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
|
||||
@SuppressWarnings("unchecked")
|
||||
public HibernateJpaVendorAdapter() {
|
||||
ClassLoader cl = HibernateJpaVendorAdapter.class.getClassLoader();
|
||||
Class<? extends EntityManagerFactory> emfIfcToUse;
|
||||
Class<? extends EntityManager> emIfcToUse;
|
||||
Class<?> providerClass;
|
||||
PersistenceProvider providerToUse;
|
||||
try {
|
||||
try {
|
||||
// Try Hibernate 4.3/5.0's org.hibernate.jpa package in order to avoid deprecation warnings
|
||||
emfIfcToUse = (Class<? extends EntityManagerFactory>) cl.loadClass("org.hibernate.jpa.HibernateEntityManagerFactory");
|
||||
emIfcToUse = (Class<? extends EntityManager>) cl.loadClass("org.hibernate.jpa.HibernateEntityManager");
|
||||
providerClass = cl.loadClass("org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Fall back to Hibernate 3.6-4.2 org.hibernate.ejb package
|
||||
emfIfcToUse = (Class<? extends EntityManagerFactory>) cl.loadClass("org.hibernate.ejb.HibernateEntityManagerFactory");
|
||||
emIfcToUse = (Class<? extends EntityManager>) cl.loadClass("org.hibernate.ejb.HibernateEntityManager");
|
||||
providerClass = cl.loadClass("org.springframework.orm.jpa.vendor.SpringHibernateEjbPersistenceProvider");
|
||||
}
|
||||
providerToUse = (PersistenceProvider) providerClass.newInstance();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Failed to determine Hibernate PersistenceProvider", ex);
|
||||
}
|
||||
this.persistenceProvider = providerToUse;
|
||||
this.entityManagerFactoryInterface = emfIfcToUse;
|
||||
this.entityManagerInterface = emIfcToUse;
|
||||
this.persistenceProvider = new SpringHibernateJpaPersistenceProvider();
|
||||
this.entityManagerFactoryInterface = HibernateEntityManagerFactory.class;
|
||||
this.entityManagerInterface = HibernateEntityManager.class;
|
||||
}
|
||||
|
||||
|
||||
@@ -170,15 +142,15 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
|
||||
protected Class<?> determineDatabaseDialectClass(Database database) {
|
||||
switch (database) {
|
||||
case DB2: return DB2Dialect.class;
|
||||
case DERBY: return DerbyDialect.class; // DerbyDialect deprecated in 4.x
|
||||
case DERBY: return DerbyDialect.class;
|
||||
case H2: return H2Dialect.class;
|
||||
case HSQL: return HSQLDialect.class;
|
||||
case INFORMIX: return InformixDialect.class;
|
||||
case MYSQL: return MySQLDialect.class;
|
||||
case ORACLE: return Oracle9iDialect.class;
|
||||
case POSTGRESQL: return PostgreSQLDialect.class; // PostgreSQLDialect deprecated in 4.x
|
||||
case POSTGRESQL: return PostgreSQLDialect.class;
|
||||
case SQL_SERVER: return SQLServerDialect.class;
|
||||
case SYBASE: return org.hibernate.dialect.SybaseDialect.class; // SybaseDialect deprecated in 3.6 but not 4.x
|
||||
case SYBASE: return org.hibernate.dialect.SybaseDialect.class;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -16,39 +16,45 @@
|
||||
|
||||
package org.springframework.orm.jpa.vendor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
|
||||
import org.hibernate.ejb.Ejb3Configuration;
|
||||
import org.hibernate.ejb.HibernatePersistence;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
|
||||
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
|
||||
|
||||
import org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo;
|
||||
|
||||
/**
|
||||
* Spring-specific subclass of the standard {@link HibernatePersistence}
|
||||
* provider from the {@code org.hibernate.ejb} package, adding support for
|
||||
* Spring-specific subclass of the standard {@link HibernatePersistenceProvider}
|
||||
* from the {@code org.hibernate.jpa} package, adding support for
|
||||
* {@link SmartPersistenceUnitInfo#getManagedPackages()}.
|
||||
*
|
||||
* <p>Compatible with Hibernate 3.6 as well as 4.0-4.2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Joris Kuipers
|
||||
* @since 4.1
|
||||
* @see Ejb3Configuration#addPackage
|
||||
* @see Configuration#addPackage
|
||||
*/
|
||||
class SpringHibernateEjbPersistenceProvider extends HibernatePersistence {
|
||||
class SpringHibernateJpaPersistenceProvider extends HibernatePersistenceProvider {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties) {
|
||||
Ejb3Configuration cfg = new Ejb3Configuration();
|
||||
final List<String> mergedClassesAndPackages = new ArrayList<String>(info.getManagedClassNames());
|
||||
if (info instanceof SmartPersistenceUnitInfo) {
|
||||
for (String managedPackage : ((SmartPersistenceUnitInfo) info).getManagedPackages()) {
|
||||
cfg.addPackage(managedPackage);
|
||||
}
|
||||
mergedClassesAndPackages.addAll(((SmartPersistenceUnitInfo) info).getManagedPackages());
|
||||
}
|
||||
Ejb3Configuration configured = cfg.configure(info, properties);
|
||||
return (configured != null ? configured.buildEntityManagerFactory() : null);
|
||||
return new EntityManagerFactoryBuilderImpl(
|
||||
new PersistenceUnitInfoDescriptor(info) {
|
||||
@Override
|
||||
public List<String> getManagedClassNames() {
|
||||
return mergedClassesAndPackages;
|
||||
}
|
||||
}, properties).build();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user