/* * Copyright 2002-2008 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.transaction; /** * This is the central interface in Spring's transaction infrastructure. * Applications can use this directly, but it is not primarily meant as API: * Typically, applications will work with either TransactionTemplate or * declarative transaction demarcation through AOP. * * <p>For implementors, it is recommended to derive from the provided * {@link org.springframework.transaction.support.AbstractPlatformTransactionManager} * class, which pre-implements the defined propagation behavior and takes care * of transaction synchronization handling. Subclasses have to implement * template methods for specific states of the underlying transaction, * for example: begin, suspend, resume, commit. * * <p>The default implementations of this strategy interface are * {@link org.springframework.transaction.jta.JtaTransactionManager} and * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}, * which can serve as an implementation guide for other transaction strategies. * * @author Rod Johnson * @author Juergen Hoeller * @since 16.05.2003 * @see org.springframework.transaction.support.TransactionTemplate * @see org.springframework.transaction.interceptor.TransactionInterceptor * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean */ public interface PlatformTransactionManager { /** * Return a currently active transaction or create a new one, according to * the specified propagation behavior. * <p>Note that parameters like isolation level or timeout will only be applied * to new transactions, and thus be ignored when participating in active ones. * <p>Furthermore, not all transaction definition settings will be supported * by every transaction manager: A proper transaction manager implementation * should throw an exception when unsupported settings are encountered. * <p>An exception to the above rule is the read-only flag, which should be * ignored if no explicit read-only mode is supported. Essentially, the * read-only flag is just a hint for potential optimization. * @param definition TransactionDefinition instance (can be <code>null</code> for defaults), * describing propagation behavior, isolation level, timeout etc. * @return transaction status object representing the new or current transaction * @throws TransactionException in case of lookup, creation, or system errors * @throws IllegalTransactionStateException if the given transaction definition * cannot be executed (for example, if a currently active transaction is in * conflict with the specified propagation behavior) * @see TransactionDefinition#getPropagationBehavior * @see TransactionDefinition#getIsolationLevel * @see TransactionDefinition#getTimeout * @see TransactionDefinition#isReadOnly */ TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; /** * Commit the given transaction, with regard to its status. If the transaction * has been marked rollback-only programmatically, perform a rollback. * <p>If the transaction wasn't a new one, omit the commit for proper * participation in the surrounding transaction. If a previous transaction * has been suspended to be able to create a new one, resume the previous * transaction after committing the new one. * <p>Note that when the commit call completes, no matter if normally or * throwing an exception, the transaction must be fully completed and * cleaned up. No rollback call should be expected in such a case. * <p>If this method throws an exception other than a TransactionException, * then some before-commit error caused the commit attempt to fail. For * example, an O/R Mapping tool might have tried to flush changes to the * database right before commit, with the resulting DataAccessException * causing the transaction to fail. The original exception will be * propagated to the caller of this commit method in such a case. * @param status object returned by the <code>getTransaction</code> method * @throws UnexpectedRollbackException in case of an unexpected rollback * that the transaction coordinator initiated * @throws HeuristicCompletionException in case of a transaction failure * caused by a heuristic decision on the side of the transaction coordinator * @throws TransactionSystemException in case of commit or system errors * (typically caused by fundamental resource failures) * @throws IllegalTransactionStateException if the given transaction * is already completed (that is, committed or rolled back) * @see TransactionStatus#setRollbackOnly */ void commit(TransactionStatus status) throws TransactionException; /** * Perform a rollback of the given transaction. * <p>If the transaction wasn't a new one, just set it rollback-only for proper * participation in the surrounding transaction. If a previous transaction * has been suspended to be able to create a new one, resume the previous * transaction after rolling back the new one. * <p><b>Do not call rollback on a transaction if commit threw an exception.</b> * The transaction will already have been completed and cleaned up when commit * returns, even in case of a commit exception. Consequently, a rollback call * after commit failure will lead to an IllegalTransactionStateException. * @param status object returned by the <code>getTransaction</code> method * @throws TransactionSystemException in case of rollback or system errors * (typically caused by fundamental resource failures) * @throws IllegalTransactionStateException if the given transaction * is already completed (that is, committed or rolled back) */ void rollback(TransactionStatus status) throws TransactionException; }1、編程式
/* * Copyright 2002-2007 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.transaction.support; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionSystemException; /** * Template class that simplifies programmatic transaction demarcation and * transaction exception handling. * * <p>The central method is {@link #execute}, supporting transactional code that * implements the {@link TransactionCallback} interface. This template handles * the transaction lifecycle and possible exceptions such that neither the * TransactionCallback implementation nor the calling code needs to explicitly * handle transactions. * * <p>Typical usage: Allows for writing low-level data access objects that use * resources such as JDBC DataSources but are not transaction-aware themselves. * Instead, they can implicitly participate in transactions handled by higher-level * application services utilizing this class, making calls to the low-level * services via an inner-class callback object. * * <p>Can be used within a service implementation via direct instantiation with * a transaction manager reference, or get prepared in an application context * and passed to services as bean reference. Note: The transaction manager should * always be configured as bean in the application context: in the first case given * to the service directly, in the second case given to the prepared template. * * <p>Supports setting the propagation behavior and the isolation level by name, * for convenient configuration in context definitions. * * @author Juergen Hoeller * @since 17.03.2003 * @see #execute * @see #setTransactionManager * @see org.springframework.transaction.PlatformTransactionManager */ public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); private PlatformTransactionManager transactionManager; /** * Construct a new TransactionTemplate for bean usage. * <p>Note: The PlatformTransactionManager needs to be set before * any <code>execute</code> calls. * @see #setTransactionManager */ public TransactionTemplate() { } /** * Construct a new TransactionTemplate using the given transaction manager. * @param transactionManager the transaction management strategy to be used */ public TransactionTemplate(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } /** * Construct a new TransactionTemplate using the given transaction manager, * taking its default settings from the given transaction definition. * @param transactionManager the transaction management strategy to be used * @param transactionDefinition the transaction definition to copy the * default settings from. Local properties can still be set to change values. */ public TransactionTemplate(PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition) { super(transactionDefinition); this.transactionManager = transactionManager; } /** * Set the transaction management strategy to be used. */ public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } /** * Return the transaction management strategy to be used. */ public PlatformTransactionManager getTransactionManager() { return this.transactionManager; } public void afterPropertiesSet() { if (this.transactionManager == null) { throw new IllegalArgumentException("Property 'transactionManager' is required"); } } public Object execute(TransactionCallback action) throws TransactionException { if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } else { TransactionStatus status = this.transactionManager.getTransaction(this); Object result = null; try { result = action.doInTransaction(status); } catch (RuntimeException ex) { // Transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } catch (Error err) { // Transactional code threw error -> rollback rollbackOnException(status, err); throw err; } this.transactionManager.commit(status); return result; } } /** * Perform a rollback, handling rollback exceptions properly. * @param status object representing the transaction * @param ex the thrown application exception or error * @throws TransactionException in case of a rollback error */ private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException { logger.debug("Initiating transaction rollback on application exception", ex); try { this.transactionManager.rollback(status); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } catch (Error err) { logger.error("Application exception overridden by rollback error", ex); throw err; } } }
/* * Copyright 2002-2006 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction; import java.sql.Connection; /** * Interface that defines Spring-compliant transaction properties. * Based on the propagation behavior definitions analogous to EJB CMT attributes. * * <p>Note that isolation level and timeout settings will not get applied unless * an actual new transaction gets started. As only {@link #PROPAGATION_REQUIRED}, * {@link #PROPAGATION_REQUIRES_NEW} and {@link #PROPAGATION_NESTED} can cause * that, it usually doesn't make sense to specify those settings in other cases. * Furthermore, be aware that not all transaction managers will support those * advanced features and thus might throw corresponding exceptions when given * non-default values. * * <p>The {@link #isReadOnly() read-only flag} applies to any transaction context, * whether backed by an actual resource transaction or operating non-transactionally * at the resource level. In the latter case, the flag will only apply to managed * resources within the application, such as a Hibernate <code>Session</code>. * * @author Juergen Hoeller * @since 08.05.2003 * @see PlatformTransactionManager#getTransaction(TransactionDefinition) * @see org.springframework.transaction.support.DefaultTransactionDefinition * @see org.springframework.transaction.interceptor.TransactionAttribute */ public interface TransactionDefinition { /** * Support a current transaction; create a new one if none exists. * Analogous to the EJB transaction attribute of the same name. * <p>This is typically the default setting of a transaction definition, * and typically defines a transaction synchronization scope. */ int PROPAGATION_REQUIRED = 0; /** * Support a current transaction; execute non-transactionally if none exists. * Analogous to the EJB transaction attribute of the same name. * <p><b>NOTE:</b> For transaction managers with transaction synchronization, * <code>PROPAGATION_SUPPORTS</code> is slightly different from no transaction * at all, as it defines a transaction scope that synchronization might apply to. * As a consequence, the same resources (a JDBC <code>Connection</code>, a * Hibernate <code>Session</code>, etc) will be shared for the entire specified * scope. Note that the exact behavior depends on the actual synchronization * configuration of the transaction manager! * <p>In general, use <code>PROPAGATION_SUPPORTS</code> with care! In particular, do * not rely on <code>PROPAGATION_REQUIRED</code> or <code>PROPAGATION_REQUIRES_NEW</code> * <i>within</i> a <code>PROPAGATION_SUPPORTS</code> scope (which may lead to * synchronization conflicts at runtime). If such nesting is unavoidable, make sure * to configure your transaction manager appropriately (typically switching to * "synchronization on actual transaction"). * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION */ int PROPAGATION_SUPPORTS = 1; /** * Support a current transaction; throw an exception if no current transaction * exists. Analogous to the EJB transaction attribute of the same name. * <p>Note that transaction synchronization within a <code>PROPAGATION_MANDATORY</code> * scope will always be driven by the surrounding transaction. */ int PROPAGATION_MANDATORY = 2; /** * Create a new transaction, suspending the current transaction if one exists. * Analogous to the EJB transaction attribute of the same name. * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box * on all transaction managers. This in particular applies to * {@link org.springframework.transaction.jta.JtaTransactionManager}, * which requires the <code>javax.transaction.TransactionManager</code> * to be made available it to it (which is server-specific in standard J2EE). * <p>A <code>PROPAGATION_REQUIRES_NEW</code> scope always defines its own * transaction synchronizations. Existing synchronizations will be suspended * and resumed appropriately. * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */ int PROPAGATION_REQUIRES_NEW = 3; /** * Do not support a current transaction; rather always execute non-transactionally. * Analogous to the EJB transaction attribute of the same name. * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box * on all transaction managers. This in particular applies to * {@link org.springframework.transaction.jta.JtaTransactionManager}, * which requires the <code>javax.transaction.TransactionManager</code> * to be made available it to it (which is server-specific in standard J2EE). * <p>Note that transaction synchronization is <i>not</i> available within a * <code>PROPAGATION_NOT_SUPPORTED</code> scope. Existing synchronizations * will be suspended and resumed appropriately. * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */ int PROPAGATION_NOT_SUPPORTED = 4; /** * Do not support a current transaction; throw an exception if a current transaction * exists. Analogous to the EJB transaction attribute of the same name. * <p>Note that transaction synchronization is <i>not</i> available within a * <code>PROPAGATION_NEVER</code> scope. */ int PROPAGATION_NEVER = 5; /** * Execute within a nested transaction if a current transaction exists, * behave like {@link #PROPAGATION_REQUIRED} else. There is no analogous * feature in EJB. * <p><b>NOTE:</b> Actual creation of a nested transaction will only work on specific * transaction managers. Out of the box, this only applies to the JDBC * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager} * when working on a JDBC 3.0 driver. Some JTA providers might support * nested transactions as well. * @see org.springframework.jdbc.datasource.DataSourceTransactionManager */ int PROPAGATION_NESTED = 6; /** * Use the default isolation level of the underlying datastore. * All other levels correspond to the JDBC isolation levels. * @see java.sql.Connection */ int ISOLATION_DEFAULT = -1; /** * Indicates that dirty reads, non-repeatable reads and phantom reads * can occur. * <p>This level allows a row changed by one transaction to be read by * another transaction before any changes in that row have been committed * (a "dirty read"). If any of the changes are rolled back, the second * transaction will have retrieved an invalid row. * @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED */ int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED; /** * Indicates that dirty reads are prevented; non-repeatable reads and * phantom reads can occur. * <p>This level only prohibits a transaction from reading a row * with uncommitted changes in it. * @see java.sql.Connection#TRANSACTION_READ_COMMITTED */ int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED; /** * Indicates that dirty reads and non-repeatable reads are prevented; * phantom reads can occur. * <p>This level prohibits a transaction from reading a row with * uncommitted changes in it, and it also prohibits the situation * where one transaction reads a row, a second transaction alters * the row, and the first transaction rereads the row, getting * different values the second time (a "non-repeatable read"). * @see java.sql.Connection#TRANSACTION_REPEATABLE_READ */ int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ; /** * Indicates that dirty reads, non-repeatable reads and phantom reads * are prevented. * <p>This level includes the prohibitions in * {@link #ISOLATION_REPEATABLE_READ} and further prohibits the * situation where one transaction reads all rows that satisfy a * <code>WHERE</code> condition, a second transaction inserts a * row that satisfies that <code>WHERE</code> condition, and the * first transaction rereads for the same condition, retrieving * the additional "phantom" row in the second read. * @see java.sql.Connection#TRANSACTION_SERIALIZABLE */ int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE; /** * Use the default timeout of the underlying transaction system, * or none if timeouts are not supported. */ int TIMEOUT_DEFAULT = -1; /** * Return the propagation behavior. * <p>Must return one of the <code>PROPAGATION_XXX</code> constants * defined on {@link TransactionDefinition this interface}. * @return the propagation behavior * @see #PROPAGATION_REQUIRED * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive() */ int getPropagationBehavior(); /** * Return the isolation level. * <p>Must return one of the <code>ISOLATION_XXX</code> constants * defined on {@link TransactionDefinition this interface}. * <p>Only makes sense in combination with {@link #PROPAGATION_REQUIRED} * or {@link #PROPAGATION_REQUIRES_NEW}. * <p>Note that a transaction manager that does not support custom * isolation levels will throw an exception when given any other level * than {@link #ISOLATION_DEFAULT}. * @return the isolation level */ int getIsolationLevel(); /** * Return the transaction timeout. * <p>Must return a number of seconds, or {@link #TIMEOUT_DEFAULT}. * <p>Only makes sense in combination with {@link #PROPAGATION_REQUIRED} * or {@link #PROPAGATION_REQUIRES_NEW}. * <p>Note that a transaction manager that does not support timeouts * will throw an exception when given any other timeout than * {@link #TIMEOUT_DEFAULT}. * @return the transaction timeout */ int getTimeout(); /** * Return whether to optimize as a read-only transaction. * <p>The read-only flag applies to any transaction context, whether * backed by an actual resource transaction * ({@link #PROPAGATION_REQUIRED}/{@link #PROPAGATION_REQUIRES_NEW}) or * operating non-transactionally at the resource level * ({@link #PROPAGATION_SUPPORTS}). In the latter case, the flag will * only apply to managed resources within the application, such as a * Hibernate <code>Session</code>. * <p>This just serves as a hint for the actual transaction subsystem; * it will <i>not necessarily</i> cause failure of write access attempts. * A transaction manager that cannot interpret the read-only hint will * <i>not</i> throw an exception when asked for a read-only transaction. * @return <code>true</code> if the transaction is to be optimized as read-only * @see org.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean) * @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly() */ boolean isReadOnly(); /** * Return the name of this transaction. Can be <code>null</code>. * <p>This will be used as the transaction name to be shown in a * transaction monitor, if applicable (for example, WebLogic's). * <p>In case of Spring's declarative transactions, the exposed name * must (and will) be the * <code>fully-qualified class name + "." + method name</code> * (by default). * @return the name of this transaction * @see org.springframework.transaction.interceptor.TransactionAspectSupport * @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName() */ String getName(); }<3> execute方法參數:
/* * Copyright 2002-2007 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.transaction.support; import org.springframework.transaction.TransactionStatus; /** * Callback interface for transactional code. Used with {@link TransactionTemplate}'s * <code>execute</code> method, often as anonymous class within a method implementation. * * <p>Typically used to assemble various calls to transaction-unaware data access * services into a higher-level service method with transaction demarcation. As an * alternative, consider the use of declarative transaction demarcation (e.g. through * Spring's {@link org.springframework.transaction.annotation.Transactional} annotation). * * @author Juergen Hoeller * @since 17.03.2003 * @see TransactionTemplate * @see CallbackPreferringPlatformTransactionManager */ public interface TransactionCallback { /** * Gets called by {@link TransactionTemplate#execute} within a transactional context. * Does not need to care about transactions itself, although it can retrieve * and influence the status of the current transaction via the given status * object, e.g. setting rollback-only. * * <p>Allows for returning a result object created within the transaction, i.e. * a domain object or a collection of domain objects. A RuntimeException thrown * by the callback is treated as application exception that enforces a rollback. * An exception gets propagated to the caller of the template. * * @param status associated transaction status * @return a result object, or <code>null</code> * @see TransactionTemplate#execute * @see CallbackPreferringPlatformTransactionManager#execute */ Object doInTransaction(TransactionStatus status); }TransactionStatus.java 源碼
/* * Copyright 2002-2007 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.transaction; /** * Representation of the status of a transaction. * * <p>Transactional code can use this to retrieve status information, * and to programmatically request a rollback (instead of throwing * an exception that causes an implicit rollback). * * <p>Derives from the SavepointManager interface to provide access * to savepoint management facilities. Note that savepoint management * is only available if supported by the underlying transaction manager. * * @author Juergen Hoeller * @since 27.03.2003 * @see #setRollbackOnly() * @see PlatformTransactionManager#getTransaction * @see org.springframework.transaction.support.TransactionCallback#doInTransaction * @see org.springframework.transaction.interceptor.TransactionInterceptor#currentTransactionStatus() */ public interface TransactionStatus extends SavepointManager { /** * Return whether the present transaction is new (else participating * in an existing transaction, or potentially not running in an * actual transaction in the first place). */ boolean isNewTransaction(); /** * Return whether this transaction internally carries a savepoint, * that is, has been created as nested transaction based on a savepoint. * <p>This method is mainly here for diagnostic purposes, alongside * {@link #isNewTransaction()}. For programmatic handling of custom * savepoints, use SavepointManager's operations. * @see #isNewTransaction() * @see #createSavepoint * @see #rollbackToSavepoint(Object) * @see #releaseSavepoint(Object) */ boolean hasSavepoint(); /** * Set the transaction rollback-only. This instructs the transaction manager * that the only possible outcome of the transaction may be a rollback, as * alternative to throwing an exception which would in turn trigger a rollback. * <p>This is mainly intended for transactions managed by * {@link org.springframework.transaction.support.TransactionTemplate} or * {@link org.springframework.transaction.interceptor.TransactionInterceptor}, * where the actual commit/rollback decision is made by the container. * @see org.springframework.transaction.support.TransactionCallback#doInTransaction * @see org.springframework.transaction.interceptor.TransactionAttribute#rollbackOn */ void setRollbackOnly(); /** * Return whether the transaction has been marked as rollback-only * (either by the application or by the transaction infrastructure). */ boolean isRollbackOnly(); /** * Return whether this transaction is completed, that is, * whether it has already been committed or rolled back. * @see PlatformTransactionManager#commit * @see PlatformTransactionManager#rollback */ boolean isCompleted(); }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="dataSourceTest" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!-- 數據庫連接 --> <property name="user" value="root"></property> <property name="password" value="test"></property> <property name="jdbcUrl" value="jdbc:oracle:thin:@127.0.0.1:1521:tran"></property> <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"></property> <!-- 鏈接池配置 --> <property name="initialPoolSize" value="10"></property> <property name="maxIdleTime" value="20"></property> <property name="checkoutTimeout" value="2000"></property> <property name="maxStatementsPerConnection" value="30"></property> </bean> <!-- sessionFactoryTest --> <bean id="sessionFactoryTest" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSourceTest" /> </property> <property name="mappingResources"> <list> <value>com/lxh/transaction8/BankAccount.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.OracleDialect </prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.connection.release_mode">auto</prop> <prop key="hibernate.current_session_context_class">thread</prop> <!-- 事務相關 --> <!-- <prop key="current_session_context_class">thread</prop> --> <!-- <prop key="connection.release_mode">auto</prop> --> <!-- <prop key="transaction.auto_close_session">false</prop> --> <prop key="connection.autocommit">false</prop> <!-- 二級緩存 --> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_second_level_cache">true</prop> </props> </property> </bean> <!-- JdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource"> <ref local="dataSourceTest" /> </property> </bean> <!-- spring事務管理 --> <bean id="transactinManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref bean="dataSourceTest" /> </property> </bean> </beans>
package com.lxh.transaction8; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; public class TransactionCallbackImpl implements TransactionCallback { // 執行語句和JdbcTemplate private String sql[]; private JdbcTemplate jt; // constructor public TransactionCallbackImpl(String sql[],JdbcTemplate jt){ this.sql = sql; this.jt = jt; } @Override public Object doInTransaction(TransactionStatus arg0) { return this.jt.batchUpdate(sql); } }<3> BankAccountDaoImpl.Java與dao.xml文件
package com.lxh.transaction8; import java.io.Serializable; import org.apache.log4j.Logger; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.transaction.support.TransactionTemplate; public class BankAccountDaoImpl extends HibernateDaoSupport implements BankAccountDao { // 日誌 private final static Logger logger = Logger .getLogger(BankAccountDaoImpl.class); // 屬性 private JdbcTemplate jt; private PlatformTransactionManager transactionManager; public void setJt(JdbcTemplate jt) { this.jt = jt; } public JdbcTemplate getJt() { return jt; } public PlatformTransactionManager getTransactionManager() { return transactionManager; } public void setTransactionManager( PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } // 查詢用戶餘額 public int getUserBalanceById(Serializable id) { int balance = 0; // try { // 查詢語句 balance = Integer.parseInt(this.jt.queryForObject( "select ba.balance from BankAccount ba where ba.id = '" + id + "'", String.class).toString()); } catch (Exception e) { logger.error("" + e.getMessage()); } // 返回 return balance; } // 轉帳 public boolean transferMoney(Serializable fromId, Serializable toId, int tradeMoney) { // 標識 boolean flag = false; // String sql[] = new String[2]; sql[0] = "update BankAccount ba set ba.balance = ba.balance - " + tradeMoney + " where ba.id='" + fromId + "'"; sql[1] = "update BankAccount ba set ba.balance = ba.balance + " + tradeMoney + " where ba.id='" + toId + "'"; // 執行結果 int result[] = new int[sql.length]; // spring 事務 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); TransactionTemplate tt = new TransactionTemplate(transactionManager, def);// TransactionTemplate 能夠採用setter方法注入獲得。 TransactionCallbackImpl tci = new TransactionCallbackImpl(sql, jt); result = (int[]) tt.execute(tci); // 是否提交事務 boolean commit = true; for (int j = 0; j < result.length; j++) { if (result[j] == 0) { // 未正常執行 commit = false; transactionManager.rollback(status); break; } } // 成功才提交事務 if (commit) { transactionManager.commit(status); flag = true; } // 返回 return flag; } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- bankAccountDao --> <bean id="bankAccountDao" class="com.lxh.transaction8.BankAccountDaoImpl" singleton="false"> <property name="sessionFactory" ref="sessionFactoryTest"></property> <property name="jt" ref="jdbcTemplate" /> <property name="transactionManager" ref="transactinManager" /> </bean> </beans>
package com.lxh.transaction8; import java.io.Serializable; import org.apache.log4j.Logger; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.transaction.support.TransactionTemplate; public class BankAccountDaoImpl extends HibernateDaoSupport implements BankAccountDao { // 日誌 private final static Logger logger = Logger .getLogger(BankAccountDaoImpl.class); // 屬性 private JdbcTemplate jt; private PlatformTransactionManager transactionManager; public void setJt(JdbcTemplate jt) { this.jt = jt; } public JdbcTemplate getJt() { return jt; } public PlatformTransactionManager getTransactionManager() { return transactionManager; } public void setTransactionManager( PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } // 查詢用戶餘額 public int getUserBalanceById(Serializable id) { int balance = 0; // try { // 查詢語句 balance = Integer.parseInt(this.jt.queryForObject( "select ba.balance from BankAccount ba where ba.id = '" + id + "'", String.class).toString()); } catch (Exception e) { logger.error("" + e.getMessage()); } // 返回 return balance; } // 轉帳 public boolean transferMoney(Serializable fromId, Serializable toId, int tradeMoney) { // 標識 boolean flag = false; // String sql[] = new String[2]; sql[0] = "update BankAccount ba set ba.balance = ba.balance - " + tradeMoney + " where ba.id='" + fromId + "'"; sql[1] = "update BankAccount ba set ba.balance = ba.balance + " + tradeMoney + " where ba.id='" + toId + "'"; // 執行結果 int result[] = new int[sql.length]; // spring 事務 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); result = this.jt.batchUpdate(sql); // 是否提交事務 boolean commit = true; for (int j = 0; j < result.length; j++) { if (result[j] == 0) { // 錯誤執行 commit = false; transactionManager.rollback(status); break; } } // 成功才提交事務 if (commit) { transactionManager.commit(status); flag = true; } // 返回 return flag; } }