Spring提供了编程式事务管理(programmatic transaction management)与声明式事务管理(declarative transaction management)。由于编程式事务管理会导致Spring框架侵入代码,而且变更复杂,故不赞成使用编程式事务管理。因此该篇笔记以声明式事务管理为主。
事务是一组原子操作的工作单元,在数据库存取中,就是一组SQL指令,它们必须全部执行成功,因为某个原因未全部成功,则先前所有执行过的SQL指令都要被撤销。
1. JDBC的事务管理
- try{
- connection.setAutoCommit(false);
- ...//一连串SQL操作
- connection.commit();
- }catch(SQLException){
- //发生错误,撤销所有变更
- connection.rollback();
- }
2. Spring的事务管理
Spring对JDBC的事务管理加以封装,关键是对org.springframework.transaction.PlatformTransactionManager接口的实现,DataSourceTransactionManager,HibernateTransactionManager等实现了此接口:
- public interface PlatformTransactionManager {
- /**
- * Return a currently active transaction or create a new one, according to
- * the specified propagation behavior.
- * @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
- */
- 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
- */
- 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
- */
- void rollback(TransactionStatus status) throws TransactionException;
- }
其中,org.springframework.transaction.TransactionDefinition接口的实例定义了事务的隔离程度、传播行为、超时、只读等。
- public interface TransactionDefinition {
- int PROPAGATION_REQUIRED = 0;
- int PROPAGATION_SUPPORTS = 1;
- int PROPAGATION_MANDATORY = 2;
- int PROPAGATION_REQUIRES_NEW = 3;
- int PROPAGATION_NOT_SUPPORTED = 4;
- int PROPAGATION_NEVER = 5;
- int PROPAGATION_NESTED = 6;
- int ISOLATION_DEFAULT = -1;
- int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
- int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
- int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
- int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
- int TIMEOUT_DEFAULT = -1;
- /** Return the propagation behavior. */
- int getPropagationBehavior();
- /** Return the isolation level. */
- int getIsolationLevel();
- /** Return the transaction timeout. */
- int getTimeout();
- /*** Return whether to optimize as a read-only transaction. */
- 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).
- */
- String getName();
- }
org.springframework.transaction.TransactionStatus代表着一个新的事务发起或已经存在的事务,通过它可以控制事务的执行、设置状态。
- 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.
- */
- 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.
- */
- void setRollbackOnly();
- /**
- * Return whether the transaction has been marked as rollback-only
- * (either by the application or by the transaction infrastructure).
- */
- boolean isRollbackOnly();
- /**
- * Flush the underlying session to the datastore, if applicable: */
- void flush();
- /**
- * Return whether this transaction is completed, that is,
- * whether it has already been committed or rolled back. */
- boolean isCompleted();
- }
编程事务管理举例:
- public class TransactionDAO {
- private JdbcTemplate jdbcTemplate;
- private DataSourceTransactionManager transactionManager;
- private DefaultTransactionDefinition def;
- public void setDataSource(DataSource dataSource){
- jdbcTemplate=new JdbcTemplate(dataSource);
- transactionManager=
- new DataSourceTransactionManager(dataSource);
- def=new DefaultTransactionDefinition();
- def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
- }
- public void insert(User user){
- TransactionStatus status=
- transactionManager.getTransaction(def);
- try{
- jdbcTemplate.update("insert into user(name) values('"+user.getName()+"')");
- jdbcTemplate.update("insert");
- }catch(DataAccessException e){
- transactionManager.rollback(status);
- throw e;
- }
- transactionManager.commit(status);
- }
- }
声明事务管理:
声明式事务管理依赖它的AOP框架,使用它只需在定义文件中进行配置,事务管理不会侵入所开发的组件,而且便于修改。简单的Bean定义文件配置如下:
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- <bean id="userDAO" class="org.spring.dao.UserDAO">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- <bean id="userDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
- <property name="proxyInterfaces">
- <list>
- <value>org.spring.dao.IUserDAO</value>
- </list>
- </property>
- <property name="target" ref="userDAO"></property>
- <property name="transactionManager" ref="transactionManager"></property>
- <property name="transactionAttributes">
- <props>
- <prop key="insert*">PROPAGATION_REQUIRED</prop>
- </props>
- </property>
- </bean>
transactionManager、userDAO使用同一个DataSource,在org.springframework.transaction.interceptor.TransactionProxyFactoryBean代理对象中设置被代理接口、被代理目标实例、事务管理器以及事务属性。这样事务管理会自动介入指定的方法前后。如上,userDAO中以insert开头的方法都会被纳入事务管理,即方法执行过程中发生错误,则方法中所有先前的操作都自动撤回,否则正常提交。
事务属性可以在TransactionDefinition接口中找到。对于目标方法可以加上多个事务属性定义,中间用","隔开。
这样配置后,就可以正常使用UserDAO了,在UserDAO类中不需要增加事务管理代码。即
IUserDAO dao=(IUserDAO)context.getBean("userDAOProxy");dao.insert(user);
也可以设置单独的Interceptor,如下:
- <bean id="transactionInterceptor"
- class="org.springframework.transaction.interceptor.TransactionInterceptor">
- <property name="transactionManager" ref="transactionManager"/>
- <property name="transactionAttributeSource"
- value="org.spring.dao.UserDAO.insert*=PROPAGATION_REQUIRED"/>
- </bean>
- <bean id="userDAOProxy1"
- class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="proxyInterfaces">
- <list>
- <value>org.spring.dao.IUserDAO</value>
- </list>
- </property>
- <property name="target" ref="userDAO"></property>
- <property name="interceptorNames">
- <list>
- <value>transactionInterceptor</value>
- </list>
- </property>
- </bean>
总结:Spring的学习笔记就到此结束了,基本内容概括的差不多了。随着学习和应用,会对Spring进行深层的补充和理解。