事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性。事务有4大特性(ACID):原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。作为企业级应用程序框架,Spring在不同的事务管理API之上定义了一个抽象层PlatformTransactionManager,应用程序开发人员不必了解底层的事务管理API,就可以使用Spring的事务管理机制。
Spring既支持编程式事务管理(也称编码式事务),也支持声明式的事务管理。编程式事务管理是指将事务管理代码嵌入到业务方法中来控制事务的提交和回滚。在编程式事务中,必须在每个业务操作中包含额外的事务管理代码。声明式事务管理是指将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。大多数情况下声明式事务管理比编程式事务管理更好用。Spring通过Spring AOP框架支持声明式事务管理。
Spring并不直接管理事务,而是提供了许多内置事务管理器实现,常用的有DataSourceTransactionManager、JdoTransactionManager、JpaTransactionManager以及HibernateTransactionManager,等等。
Spring配置文件中关于事务配置由3个组成部分,分别是DataSource、TransactionManager和代理机制。无论哪种配置方式,一般变化的只是代理机制部分。DataSource和TransactionManager这两部分只会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实现为SessionFactory,TransactionManager的实现为HibernateTransactionManager。
Spring声明式事务配置提供5种方式,而基于Annotation注解方式目前比较流行,所以这里只简单介绍基于注解方式配置Spring声明式事务。我们可以使用@Transactional注解在类或者方法上表明该类或者方法需要事务支持,被注解的类或者方法被调用时,Spring开启一个新的事务,当方法正常运行时,Spring会提交这个事务。具体例子如下:
这里需要注意的是,@Transactional注解来自org.springframework.transaction.annotation。Spring提供了@EnableTransactionManagement注解在配置类上来开启声明式事务的支持。使用@EnableTransactionManagement后,Spring容器会自动扫描注解@Transactional的方法和类。
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如,方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。事务的传播行为可以在@Transactional的属性中指定。Spring定义了7种传播行为,具体如表5-1所示。
表5-1 Spring传播行为
隔离级别定义了一个事务可能受其他并发事务影响的程度。在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务。并发虽然是必需的,但也可是会导致许多问题,并发事务所导致的问题可以分为以下3类。
针对这些问题,Spring提供了5种事务的隔离级别,具体如表5-2所示。
表5-2 Spring隔离级别
@Transactional可以通过propagation属性定义事务行为,属性值分别为REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER以及NESTED,分别对应表5-1中的内容。可以通过isolation属性定义隔离级别,属性值分别为DEFAULT、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ以及SERIALIZABLE。
还可以通过timeout属性设置事务过期时间,通过readOnly指定当前事务是否是只读事务,通过rollbackFor(noRollbackFor)指定哪个或者哪些异常可以引起(或不可以引起)事务回滚。