`
zhukang0725
  • 浏览: 15325 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

Spring中的事务管理

阅读更多
在说明Spring的事务管理之前,先说一下事务的4个特性,这四个特性简写为ACID。
1 原子性(Atomic)
2 一致性(Consistent)
3 隔离性(Isolated)
4 持久性(Duraable)

Spring中的事务管理有
针对JDBC DataSource的org.springframework.jdbc.datasource.DataSourceTransactionManager

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>

针对Hibernate的org.springframework.orm.hibernate3.HibernateTransactionManager

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>


Spring2.5中源代码如下

package org.springframework.orm.hibernate3;

import java.sql.Connection;

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.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
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;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.ResourceTransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;

public class HibernateTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {

private SessionFactory sessionFactory;

private DataSource dataSource;

private boolean autodetectDataSource = true;

private boolean prepareConnection = true;

private boolean earlyFlushBeforeCommit = false;

private Object entityInterceptor;

private SQLExceptionTranslator jdbcExceptionTranslator;

private SQLExceptionTranslator defaultJdbcExceptionTranslator;

/**
* Just needed for entityInterceptorBeanName.
* @see #setEntityInterceptorBeanName
*/
private BeanFactory beanFactory;


/**
* Create a new HibernateTransactionManager instance.
* A SessionFactory has to be set to be able to use it.
* @see #setSessionFactory
*/
public HibernateTransactionManager() {
}

/**
* Create a new HibernateTransactionManager instance.
* @param sessionFactory SessionFactory to manage transactions for
*/
public HibernateTransactionManager(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
afterPropertiesSet();
}


/**
* Set the SessionFactory that this instance should manage transactions for.
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

/**
* Return the SessionFactory that this instance should manage transactions for.
*/
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}

/**
* Set the JDBC DataSource that this instance should manage transactions for.
* The DataSource should match the one used by the Hibernate SessionFactory:
* for example, you could specify the same JNDI DataSource for both.
* <p>If the SessionFactory was configured with LocalDataSourceConnectionProvider,
* i.e. by Spring's LocalSessionFactoryBean with a specified "dataSource",
* the DataSource will be auto-detected: You can still explictly specify the
* DataSource, but you don't need to in this case.
* <p>A transactional JDBC Connection for this DataSource will be provided to
* application code accessing this DataSource directly via DataSourceUtils
* or JdbcTemplate. The Connection will be taken from the Hibernate Session.
* <p>The DataSource specified here should be the target DataSource to manage
* transactions for, not a TransactionAwareDataSourceProxy. Only data access
* code may work with TransactionAwareDataSourceProxy, while the transaction
* manager needs to work on the underlying target DataSource. If there's
* 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 org.springframework.jdbc.core.JdbcTemplate
*/
public void setDataSource(DataSource dataSource) {
if (dataSource instanceof TransactionAwareDataSourceProxy) {
// If we got a TransactionAwareDataSourceProxy, we need to perform transactions
// for its underlying target DataSource, else data access code won't see
// properly exposed transactions (i.e. transactions for the target DataSource).
this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
}
else {
this.dataSource = dataSource;
}
}

/**
* Return the JDBC DataSource that this instance manages transactions for.
*/
public DataSource getDataSource() {
return this.dataSource;
}

/**
* Set whether to autodetect a JDBC DataSource used by the Hibernate SessionFactory,
* if set via LocalSessionFactoryBean's <code>setDataSource</code>. Default is "true".
* <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;
}

/**
* Set whether to prepare the underlying JDBC Connection of a transactional
* Hibernate Session, that is, whether to apply a transaction-specific
* isolation level and/or the transaction's read-only flag to the underlying
* JDBC Connection.
* <p>Default is "true". If you turn this flag off, the transaction manager
* will not support per-transaction isolation levels anymore. It will not
* call <code>Connection.setReadOnly(true)</code> 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.
* <p>It is recommended to turn this flag off if running against Hibernate 3.1
* and a connection pool that does not reset connection settings (for example,
* Jakarta Commons DBCP). To keep this flag turned on, you can set the
* "hibernate.connection.release_mode" property to "on_close" instead,
* or consider using a smarter connection pool (for example, C3P0).
* @see java.sql.Connection#setTransactionIsolation
* @see java.sql.Connection#setReadOnly
*/
public void setPrepareConnection(boolean prepareConnection) {
this.prepareConnection = prepareConnection;
}

/**
* 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 flush before the before-commit synchronization phase, making
* flushed state visible to <code>beforeCommit</code> callbacks of registered
* {@link org.springframework.transaction.support.TransactionSynchronization}
* objects.
* <p>Such explicit flush behavior is also consistent with Spring-driven
* flushing in a JTA transaction environment, so may also be 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.
* 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 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.
* @see LocalSessionFactoryBean#setEntityInterceptor
* @see HibernateTemplate#setEntityInterceptor
* @see HibernateInterceptor#setEntityInterceptor
*/
public void setEntityInterceptor(Interceptor entityInterceptor) {
this.entityInterceptor = entityInterceptor;
}

/**
* Return the current Hibernate entity interceptor, or <code>null</code> 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 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 Interceptor) {
return (Interceptor) entityInterceptor;
}
else if (this.entityInterceptor instanceof String) {
if (this.beanFactory == null) {
throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
}
String beanName = (String) this.entityInterceptor;
return (Interceptor) this.beanFactory.getBean(beanName, Interceptor.class);
}
else {
return null;
}
}

/**
* 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.
* @see #setEntityInterceptorBeanName
*/
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}

public void afterPropertiesSet() {
if (getSessionFactory() == null) {
throw new IllegalArgumentException("Property 'sessionFactory' is required");
}
if (this.entityInterceptor instanceof String && this.beanFactory == null) {
throw new IllegalArgumentException("Property 'beanFactory' is required for 'entityInterceptorBeanName'");
}

// Check for SessionFactory's DataSource.
if (this.autodetectDataSource && getDataSource() == null) {
DataSource sfds = SessionFactoryUtils.getDataSource(getSessionFactory());
if (sfds != null) {
// Use the SessionFactory's DataSource for exposing transactions to JDBC code.
if (logger.isInfoEnabled()) {
logger.info("Using DataSource [" + sfds +
"] of Hibernate SessionFactory for HibernateTransactionManager");
}
setDataSource(sfds);
}
}
}


public Object getResourceFactory() {
return getSessionFactory();
}

protected Object doGetTransaction() {
HibernateTransactionObject txObject = new HibernateTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());

SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (sessionHolder != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found thread-bound Session [" +
SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");
}
txObject.setSessionHolder(sessionHolder, false);
}

if (getDataSource() != null) {
ConnectionHolder conHolder = (ConnectionHolder)
TransactionSynchronizationManager.getResource(getDataSource());
txObject.setConnectionHolder(conHolder);
}

return txObject;
}

protected boolean isExistingTransaction(Object transaction) {
return ((HibernateTransactionObject) transaction).hasTransaction();
}

protected void doBegin(Object transaction, TransactionDefinition definition) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;

if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
throw new IllegalTransactionStateException(
"Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
"running within DataSourceTransactionManager if told to manage the DataSource itself. " +
"It is recommended to use a single HibernateTransactionManager for all transactions " +
"on a single DataSource, no matter whether Hibernate or JDBC access.");
}

Session session = null;

try {
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
Interceptor entityInterceptor = getEntityInterceptor();
Session newSession = (entityInterceptor != null ?
getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());
if (logger.isDebugEnabled()) {
logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +
"] for Hibernate transaction");
}
txObject.setSessionHolder(new SessionHolder(newSession), true);
}

session = txObject.getSessionHolder().getSession();

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) + "]");
}
Connection con = session.connection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
}
else {
// Not allowed to change the transaction settings of the JDBC Connection.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
// We should set a specific isolation level but are not allowed to...
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' (LocalSessionFactoryBean's default)");
}
if (logger.isDebugEnabled()) {
logger.debug(
"Not preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
}
}

if (definition.isReadOnly() && txObject.isNewSessionHolder()) {
// Just set to NEVER in case of a new Session for this transaction.
session.setFlushMode(FlushMode.NEVER);
}

if (!definition.isReadOnly() && !txObject.isNewSessionHolder()) {
// We need AUTO or COMMIT for a non-read-only transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.lessThan(FlushMode.COMMIT)) {
session.setFlushMode(FlushMode.AUTO);
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
}
}

Transaction hibTx = null;

// Register transaction timeout.
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1
// Applies to all statements, also to inserts, updates and deletes!
hibTx = session.getTransaction();
hibTx.setTimeout(timeout);
hibTx.begin();
}
else {
// Open a plain Hibernate transaction without specified timeout.
hibTx = session.beginTransaction();
}

// Add the Hibernate transaction to the session holder.
txObject.getSessionHolder().setTransaction(hibTx);

// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
if (getDataSource() != null) {
Connection con = session.connection();
ConnectionHolder conHolder = new ConnectionHolder(con);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
conHolder.setTimeoutInSeconds(timeout);
}
if (logger.isDebugEnabled()) {
logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
}
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
txObject.setConnectionHolder(conHolder);
}

// Bind the session holder to the thread.
if (txObject.isNewSessionHolder()) {
TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
}
txObject.getSessionHolder().setSynchronizedWithTransaction(true);
}

catch (Exception ex) {
if (txObject.isNewSessionHolder()) {
try {
if (session.getTransaction().isActive()) {
session.getTransaction().rollback();
}
}
catch (Throwable ex2) {
logger.debug("Could not rollback Session after failed transaction begin", ex);
}
finally {
SessionFactoryUtils.closeSession(session);
}
}
throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
}
}

protected Object doSuspend(Object transaction) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
txObject.setSessionHolder(null, false);
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
txObject.setConnectionHolder(null);
ConnectionHolder connectionHolder = null;
if (getDataSource() != null) {
connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(getDataSource());
}
return new SuspendedResourcesHolder(sessionHolder, connectionHolder);
}

protected void doResume(Object transaction, Object suspendedResources) {
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
// From non-transactional code running in active transaction synchronization
// -> can be safely removed, will be closed on transaction completion.
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
TransactionSynchronizationManager.bindResource(getSessionFactory(), resourcesHolder.getSessionHolder());
if (getDataSource() != null) {
TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
}
}

protected void prepareForCommit(DefaultTransactionStatus status) {
if (this.earlyFlushBeforeCommit) {
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.NEVER);
}
}
}
}

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()) + "]");
}
try {
txObject.getSessionHolder().getTransaction().commit();
}
catch (org.hibernate.TransactionException ex) {
// assumably from commit call to the underlying JDBC connection
throw new TransactionSystemException("Could not commit Hibernate transaction", ex);
}
catch (HibernateException ex) {
// assumably failed to flush changes to database
throw convertHibernateAccessException(ex);
}
}

protected void doRollback(DefaultTransactionStatus status) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Rolling back Hibernate transaction on Session [" +
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
}
try {
txObject.getSessionHolder().getTransaction().rollback();
}
catch (org.hibernate.TransactionException ex) {
throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
}
catch (HibernateException ex) {
// Shouldn't really happen, as a rollback doesn't cause a flush.
throw convertHibernateAccessException(ex);
}
finally {
if (!txObject.isNewSessionHolder()) {
// Clear all pending inserts/updates/deletes in the Session.
// Necessary for pre-bound Sessions, to avoid inconsistent state.
txObject.getSessionHolder().getSession().clear();
}
}
}

protected void doSetRollbackOnly(DefaultTransactionStatus status) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Setting Hibernate transaction on Session [" +
SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "] rollback-only");
}
txObject.setRollbackOnly();
}

protected void doCleanupAfterCompletion(Object transaction) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;

// Remove the session holder from the thread.
if (txObject.isNewSessionHolder()) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}

// Remove the JDBC connection holder from the thread, if exposed.
if (getDataSource() != null) {
TransactionSynchronizationManager.unbindResource(getDataSource());
}

Session session = txObject.getSessionHolder().getSession();
if (this.prepareConnection && session.isConnected() && isSameConnectionForEntireSession(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();
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
}
catch (HibernateException ex) {
logger.debug("Could not access JDBC Connection of Hibernate Session", ex);
}
}

if (txObject.isNewSessionHolder()) {
if (logger.isDebugEnabled()) {
logger.debug("Closing Hibernate Session [" + SessionFactoryUtils.toString(session) +
"] after transaction");
}
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Not closing pre-bound Hibernate Session [" +
SessionFactoryUtils.toString(session) + "] after transaction");
}
if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
session.setFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
}
session.disconnect();
}
txObject.getSessionHolder().clear();
}

/**
* 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</code>.
* @param session the Hibernate Session to check
* @see org.hibernate.impl.SessionImpl#getConnectionReleaseMode()
* @see org.hibernate.ConnectionReleaseMode#ON_CLOSE
*/
protected boolean isSameConnectionForEntireSession(Session session) {
if (!(session instanceof SessionImpl)) {
// The best we can do is to assume we're safe.
return true;
}
ConnectionReleaseMode releaseMode = ((SessionImpl) session).getConnectionReleaseMode();
return ConnectionReleaseMode.ON_CLOSE.equals(releaseMode);
}


/**
* Convert the given HibernateException to an appropriate exception
* from the <code>org.springframework.dao</code> 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 (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
}
else if (GenericJDBCException.class.equals(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</code> 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 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.
* Used as transaction object by HibernateTransactionManager.
*/
private static class HibernateTransactionObject extends JdbcTransactionObjectSupport {

private SessionHolder sessionHolder;

private boolean newSessionHolder;

public void setSessionHolder(SessionHolder sessionHolder, boolean newSessionHolder) {
this.sessionHolder = sessionHolder;
this.newSessionHolder = newSessionHolder;
}

public SessionHolder getSessionHolder() {
return this.sessionHolder;
}

public boolean isNewSessionHolder() {
return this.newSessionHolder;
}

public boolean hasTransaction() {
return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);
}

public void setRollbackOnly() {
getSessionHolder().setRollbackOnly();
if (hasConnectionHolder()) {
getConnectionHolder().setRollbackOnly();
}
}

public boolean isRollbackOnly() {
return getSessionHolder().isRollbackOnly() ||
(hasConnectionHolder() && getConnectionHolder().isRollbackOnly());
}
}


/**
* Holder for suspended resources.
* Used internally by <code>doSuspend</code> and <code>doResume</code>.
*/
private static class SuspendedResourcesHolder {

private final SessionHolder sessionHolder;

private final ConnectionHolder connectionHolder;

private SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder) {
this.sessionHolder = sessionHolder;
this.connectionHolder = conHolder;
}

private SessionHolder getSessionHolder() {
return this.sessionHolder;
}

private ConnectionHolder getConnectionHolder() {
return this.connectionHolder;
}
}

}


针对JDO的org.springframework.orm.jdo.JdoTransactionManger

<bean id="transactionManager"
class="org.springframework.orm.jdo.JdoTransactionManager">
<property name="persistenceManagerFactory">
<ref bean="persistenceManagerFactory"/>
</property>
</bean>

针对OJB的org.springframework.orm.ojb.PersistenceBrokerTransactionManager

<bean id="transactionManager" class="org.springframework.orm.ojb.PersistenceBrokerTransactionManager">

</bean>

针对JTA的org.springframework.transaction.jta.JtaTransactionManager

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName">
<value>java:/TransactionManager</value>
</property>
</bean>



0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics