(一)电商系统的服务端开发中,常常会遇到须要同时更改多个数据源的场景,好比订单支付系统,用户转帐等等。在服务器出现异常的状况下,也须要保证数据的一致性,于是须要把对于多个数据源的修改封装在同一个事务中进行。Spring中的事物管理包括编程式和声明式两种。java
(二)Spring编程式事务管理spring
1)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; int getPropagationBehavior(); int getIsolationLevel(); int getTimeout(); boolean isReadOnly(); String getName(); }
接口TransactionDefinition定义了事务的7种传播行为和4种隔离级别apache
“只读事务”并非一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操做,那么JDBC驱动程序和数据库就有可能根据这种状况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。 编程
可是你非要在“只读事务”里面修改数据,也并不是不能够,只不过对于数据一致性的保护不像“读写事务”那样保险而已。 数组
所以,“只读事务”仅仅是一个性能优化的推荐配置而已,并不是强制你要这样作不可性能优化
2)TransactionStatus服务器
package org.springframework.transaction; import java.io.Flushable; public interface TransactionStatus extends SavepointManager, Flushable { boolean isNewTransaction(); boolean hasSavepoint(); void setRollbackOnly(); boolean isRollbackOnly(); @Override void flush(); boolean isCompleted(); }
3)PlatformTransactionManager并发
package org.springframework.transaction; public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
getTransaction根据事务的定义返回一个已有的或是新建一个事务。我估计是根据事务的名称返回一个已有的事务,不然则根据事务定义的传播行为、隔离级别、超时时间新建一个事务。getTransaction的实现若遇到了一个本身不支持的事务定义,则须要抛出异常。app
commit提交事务。若事务被标记为回滚,则执行回滚;若事务是新事务,那么提交以后会从新执行先前因生成该事务而暂停的其余事务;事务提交前产生的异常会致使事务提交失败。
rollback回滚事务。若先前此事务提交失败则不能够执行回滚操做。
直接使用PlatformTransactionManager接口的实现去进行事务管理比较麻烦,Spring提供了TransactionTemplate事务模版,该模板封装了事物管理者生成事物、提交事物、回滚事物的操做,方便咱们在业务代码中适用事务。因此若要使用编程式的事物管理,通常推荐使用TransactionTemplate而不是直接使用PlatformTransactionManager。
4)TransactionTemplate
package org.springframework.transaction.support; import java.lang.reflect.UndeclaredThrowableException; 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; @SuppressWarnings("serial") public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); private PlatformTransactionManager transactionManager; public TransactionTemplate() { } public TransactionTemplate(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } public TransactionTemplate(PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition) { super(transactionDefinition); this.transactionManager = transactionManager; } public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } public PlatformTransactionManager getTransactionManager() { return this.transactionManager; } @Override public void afterPropertiesSet() { if (this.transactionManager == null) { throw new IllegalArgumentException("Property 'transactionManager' is required"); } } @Override public <T> T execute(TransactionCallback<T> action) throws TransactionException { if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } else { TransactionStatus status = this.transactionManager.getTransaction(this); T result; 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; } catch (Throwable ex) { // Transactional code threw unexpected exception -> rollback rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); return result; } } 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; } } }
TransactionTemplate内部包含了事物管理者PlatformTransactionManager transactionManager,而且继承了DefaultTransactionDefinition,即拥有了事物定义的信息。
<T> T execute(TransactionCallback<T> action)是TransactionTemplate内部的一个公有方法,事物的提交或回滚,以及具体的业务逻辑都在该方法中实现,该方法的参数TransactionCallback<T> action是一个接口,须要开发人员自行实现该接口的一个方法doInTransaction(TransactionStatus status)。
在execute方法中,首先经过transactionManager.getTransaction(this)开启一个事物,获取事物状态status;而后具体的业务逻辑在doInTransaction(TransactionStatus status)中编写;最后,若无任何异常,则执行事物提交的操做transactionManager.commit(TransactionStatus status),不然,捕获异常,执行事物的回滚操做transactionManager.rollback(TransactionStatus status);在业务逻辑中,可根据具体业务须要,设置status.setRollbackOnly(),指定事物回滚。
若不须要返回值,则可使用TransactionCallbackWithoutResult代替TransactionCallback,并调用方法doInTransactionWithoutResult代替doInTransaction。
(三)Spring声明式事务管理
声明式事物管理是基于AOP的,即对调用方法进行拦截,在执行目标方法前开启一个事物,在执行目标方法后根据状况提交事物或是回滚事物。
声明式的事物管理器有两种,一种是经过在类、接口或方法上添加@Transactional注解,一种是经过xml配置文件。
1)@Transactional注解
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { @AliasFor("transactionManager") String value() default ""; @AliasFor("value") String transactionManager() default ""; Propagation propagation() default Propagation.REQUIRED; Isolation isolation() default Isolation.DEFAULT; int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; boolean readOnly() default false; String[] rollbackForClassName() default {}; Class<? extends Throwable>[] noRollbackFor() default {}; String[] noRollbackForClassName() default {}; }
value | 事物管理器 |
propagation | 设置事务的传播行为。 @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true) |
isolation | 设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的状况 |
timeout | 设置事物的超时时间,-1表明永远不超时 |
readOnly | 设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。@Transactional(readOnly=true) |
rollbackFo | 设置须要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。 @Transactional(rollbackFor={RuntimeException.class, Exception.class}) |
rollbackForClassName | 设置须要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。 @Transactional(rollbackForClassName={"RuntimeException","Exception"}) |
noRollbackFor | 设置不须要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。 @Transactional(noRollbackFor={RuntimeException.class, Exception.class}) |
noRollbackForClassName | 设置不须要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。 @Transactional(noRollbackForClassName={"RuntimeException","Exception"}) |
2)使用xml
3)注意
(三)两种事物管理方式的比较
使用编程式事物管理可使得事物的粒度细化到代码块级别,可是在不可避免地会致使业务代码的实现和事物管理的代码耦合。
使用声明式事物管理能够避免侵入式编程,不须要在业务代码中掺琐事务管理的代码,只须要在配置文件中作相关的事物规则声明,使得业务代码不受污染,可是其封装粒度只能到达方法级别。
(四)自动提交
默认状况下,数据库处于自动提交模式。每一条语句就是一个单独的事物,该语句执行完毕后,若成功则隐式提交事物,若失败则隐式回滚事物。可是对于正常的事物管理,是一组相关的操做处于一个事物之中,于是须要关闭数据库的自动提交。spring会将底层链接的自动提交设置为false。