Spring 事务介绍

1 事务特性

  • 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。

  • 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。

  • 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。

  • 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中

2 Spring 事务管理

Spring支持编程式事务管理以及声明式事务管理两种方式。

2.1 编程式事务管理

编程式事务管理是侵入性事务管理,使用TransactionTemplate或者直接使用PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate

使用TransactionTemplate不需要显式地开始事务,甚至不需要显式地提交事务。这些步骤都由模板完成。但出现异常时,应通过TransactionStatussetRollbackOnly显式回滚事务。

TransactionTemplateexecute方法接收一个TransactionCallback实例

	@Override
	@Nullable
	public <T> T execute(TransactionCallback<T> action) throws TransactionException {
		Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

		if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
			return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
		}
		else {
			TransactionStatus status = this.transactionManager.getTransaction(this);
			T result;
			try {
                // 调用 callback
				result = action.doInTransaction(status);
			}
			catch (RuntimeException | Error ex) {
				// Transactional code threw application exception -> rollback
                // 事务代码抛出应用程序异常 -> 回滚
				rollbackOnException(status, ex);
				throw ex;
			}
			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;
		}
	}

TransactionCallback是一个函数接口:

/**
 * 事务代码的回调接口。与 {@link TransactionTemplate} 的 {@code execute} 方法一起使用,通常作为方法实现中的匿名类。
 */
@FunctionalInterface
public interface TransactionCallback<T> {

   /**
	* 在事务上下文中由 {@link TransactionTemplateexecute} 调用。
	* 不需要关心事务本身,尽管它可以通过给定的状态对象检索和影响当前事务的状态,例如设置仅回滚。 
	* 允许返回在事务中创建的结果对象,即域对象或域对象的集合。
	* 回调抛出的 RuntimeException 被视为强制回滚的应用程序异常。
	* 任何此类异常都将传播给模板的调用者,除非回滚出现问题,在这种情况下将抛出 TransactionException。
    */
   @Nullable
   T doInTransaction(TransactionStatus status);

}

使用示例:

transactionTemplate.execute(new TransactionCallback() { 
	public Object doInTransaction(TransactionStatus status) { 
		try{ 
    		// 进行你的数据库操作	
        }catch (Exception e) { 
            // 仅设置事务回滚。 这指示事务管理器事务的唯一可能结果可能是回滚
            // 作为抛出异常的替代方法,该异常反过来会触发回滚
   			status.setRollbackOnly(); 
		} 
}); 

2.2 声明式事务管理

声明式事务管理注解@Transactional基于AOP实现,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。

显然声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的编程方式。唯一不足的地方就是声明式事务管理的粒度是方法级别,而编程式事务管理是可以到代码块的,但是可以通过提取方法的方式完成声明式事务管理的配置。

public @interface Transactional {

   /**
    * @author Sam Brannen
    */
   @AliasFor("transactionManager")
   String value() default "";

   /**
    * 指定事务的限定符值。
    * 可用于确定目标事务管理器
    * 匹配特定PlatformTransactionManager bean 定义的限定符值(或 bean 名称)
    */
   @AliasFor("value")
   String transactionManager() default "";

   /**
    * 事务传播类型。
    * 默认为Propagation.REQUIRED 
    */
   Propagation propagation() default Propagation.REQUIRED;

   /**
    * 事务隔离级别。
    * 默认为Isolation.DEFAULT 。
    * 专为与Propagation.REQUIRED或Propagation.REQUIRES_NEW一起使用而设计,因为它仅适用于新启动的事务。
    * 如果您希望隔离级别声明在参与具有不同隔离级别的现有事务时被拒绝,
    * 请考虑将事务管理器上的“validateExistingTransactions”标志切换为“true”
    */
   Isolation isolation() default Isolation.DEFAULT;

   /**
    * 此事务的超时时间(以秒为单位)
    * 默认为底层事务系统的默认超时。
    * 专为与Propagation.REQUIRED或Propagation.REQUIRES_NEW一起使用而设计,因为它仅适用于新启动的事务
    */
   int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

   /**
    * 如果事务实际上是只读的,则可以将其设置为true布尔标志,
    * 从而允许在运行时进行相应的优化。
    * 默认为false
    * 这只是对实际事务子系统的提示; 
    * 它不一定会导致写访问尝试失败。 
    * 无法解释只读提示的事务管理器在请求只读事务时不会抛出异常
    * 而是默默地忽略该提示
    */
   boolean readOnly() default false;

   /**
    * 定义零 (0) 个或多个异常classes ,它们必须是Throwable子类,
    * 指示哪些异常类型必须导致事务回滚。
    * 默认情况下,事务将在RuntimeException和Error上回滚,
    * 但不会在已检查的异常(业务异常)上回滚
    */
   Class<? extends Throwable>[] rollbackFor() default {};

   /**
    * 定义零 (0) 个或多个异常名称(对于必须是Throwable子类的异常)
    * 指示哪些异常类型必须导致事务回滚。
    * 这可以是完全限定类名的子字符串,目前不支持通配符。 
    * 例如, "ServletException"的值将匹配javax.servlet.ServletException及其子类。
    * 注意:仔细考虑模式的具体程度以及是否包含包信息(这不是强制性的)。 
    * 例如, "Exception"几乎可以匹配任何内容,并且可能会隐藏其他规则。 
    * 如果"Exception"旨在为所有已检查的异常定义规则,则"java.lang.Exception"将是正确的。
    * 对于更不寻常的Exception名称,例如"BaseBusinessException" ,则无需使用 FQN
    */
   String[] rollbackForClassName() default {};

   /**
    * 定义零 (0) 个或多个异常Classes
    * 它们必须是Throwable子类,指示哪些异常类型不得导致事务回滚。
    * 这是构建回滚规则的首选方法(与noRollbackForClassName )
    * 匹配异常类及其子类
    */
   Class<? extends Throwable>[] noRollbackFor() default {};

   /**
    * 定义零 (0) 个或多个异常名称(对于必须是Throwable子类的异常)
    * 指示哪些异常类型不得导致事务回滚。
    */
   String[] noRollbackForClassName() default {};

}

需要注意的是,@Transactional 基于动态代理,调用者和目标方法不在spring的同一个bean中,否则不生效。这个和动态代理有关

3 事务传播机制

枚举:org.springframework.transaction.annotation.Propagation

public enum Propagation {

	/**
	 * Spring默认的传播机制,能满足绝大部分业务需求,
	 * 如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。
	 * 如果外层没有事务,新建一个事务执行
	 */
	REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

	/**
	 * 如果外层有事务,则加入外层事务,
	 * 如果外层没有事务,则直接使用非事务方式执行。
	 * 完全依赖外层的事务
	 */
	SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

	/**
	 * 支持当前事务,如果不存在则抛出异常
	 */
	MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

	/**
	 * 该事务传播机制是每次都会新开启一个事务,
	 * 时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。
	 * 如果外层没有事务,执行当前新开启的事务即可
	 */
	REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

	/**
	 * 该传播机制不支持事务,
	 * 如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,
	 * 无论是否异常都不会回滚当前的代码
	 */
	NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

	/**
	 * 该传播机制不支持外层事务,即如果外层有事务就抛出异常
	 */
	NEVER(TransactionDefinition.PROPAGATION_NEVER),

	/**
	 * 与NEVER相反,如果外层没有事务,则抛出异常
	 */
	NESTED(TransactionDefinition.PROPAGATION_NESTED);
}

4 事务隔离级别

多事务同时运行时,就会出现并发导致事务问题

  • 脏读(Dirty read):脏读发生在一个事务读取了被另一个事务改写但尚未提交的数据时。如果这些改变在稍后被回滚了,那么第一个事务读取的数据就会是无效的。

    另一个事务回滚了

  • 不可重复读(Nonrepeatable read):不可重复读发生在一个事务执行相同的查询两次或两次以上,但每次查询结果都不相同时。这通常是由于另一个并发事务在两次查询之间更新了数据

    另一个事务修改了数据。

  • 幻读(Phantom reads):幻读和不可重复读相似。当一个事务(T1)读取几行记录后,另一个并发事务(T2)插入了一些记录时,幻读就发生了。在后来的查询中,第一个事务(T1)就会发现一些原来没有的额外记录。

    另一个事务在新增或删除了数据

在理想状态下,事务之间将完全隔离,从而可以防止这些问题发生。然而,完全隔离会影响性能,因为隔离经常涉及到锁定在数据库中的记录(甚至有时是锁表)。完全隔离要求事务相互等待来完成工作,会阻碍并发。因此,可以根据业务场景选择不同的隔离级别。

隔离级别value脏读不可重复读幻读
读未提交READ-UNCOMMITTED未解决未解决未解决
读提交READ-COMMITTED已解决未解决未解决
可重复读REPEATABLE-READ
(mysql 默认级别)
已解决已解决未解决
可串行化SERIALIZABLE已解决已解决已解决

5 只读

如果一个事务只对数据库执行读操作,那么该数据库就可能利用那个事务的只读特性,采取某些优化措施。通过把一个事务声明为只读,可以给后端数据库一个机会来应用那些它认为合适的优化措施。由于只读的优化措施是在一个事务启动时由后端数据库实施的, 因此,只有对于那些具有可能启动一个新事务的传播行为(Propagation.REQUIRES_NEWPropagation.REQUIREDPropagation.NESTED)的方法来说,将事务声明为只读才有意义。

6 事务超时

为了使一个应用程序很好地执行,它的事务不能运行太长时间。因此,声明式事务的下一个特性就是它的超时。

假设事务的运行时间变得格外的长,由于事务可能涉及对数据库的锁定,所以长时间运行的事务会不必要地占用数据库资源。这时就可以声明一个事务在特定秒数后自动回滚,不必等它自己结束。

由于超时时钟在一个事务启动的时候开始的,因此,只有对于那些具有可能启动一个新事务的传播行为(Propagation.REQUIRES_NEWPropagation.REQUIREDPropagation.NESTED)的方法来说,声明事务超时才有意义。

7 事务回滚

Spring在默认情况下,事务将在RuntimeExceptionError上回滚,但不会在已检查的异常(业务异常)上回滚

不过,可以声明在出现特定受检查异常时像运行时异常一样回滚。同样,也可以声明一个事务在出现特定的异常时不回滚,即使特定的异常是运行时异常。

推广

公众号二维码

公众号会推送更多更新,关注支持一下 _

错误的地方已更正

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring事务Spring框架中的一个重要特性,它提供了一种在应用程序中管理事务的方式,能够确保数据的一致性和完整性。Spring事务的实现是基于AOP(面向切面编程)和Java Transaction API(JTA)的。 Spring事务主要涉及以下几个方面: 1. 事务管理器(Transaction Manager):事务管理器负责管理事务的生命周期,包括事务的开始、提交、回滚以及状态的检查等操作。Spring中提供了多种事务管理器的实现,如DataSourceTransactionManager、HibernateTransactionManager、JpaTransactionManager等。 2. 事务定义(Transaction Definition):事务定义定义了事务的隔离级别、传播行为、超时时间和只读属性等信息。Spring中提供了多种事务定义的实现,如DefaultTransactionDefinition、AnnotationTransactionDefinition等。 3. 事务切面(Transaction Aspect):事务切面是通过AOP实现的,它负责在方法执行前后,或者抛出异常时开启、提交、回滚或者关闭事务。 4. 事务注解(Transaction Annotation):Spring提供了@Transactional注解,可以在方法上或者类上使用,用于标识该方法或者类需要进行事务管理。 Spring事务的使用步骤如下: 1. 配置数据源和事务管理器。 2. 在需要事务管理的方法上添加@Transactional注解。 3. 根据具体业务需求,设置事务的隔离级别、传播行为和只读属性等。 Spring事务在应用程序中的优点如下: 1. 简化了事务管理的实现,使代码更加简洁和易于维护。 2. 提高了应用程序的性能和可伸缩性,避免了数据访问冲突和资源竞争。 3. 提供了对多种数据访问技术的支持,如JDBC、Hibernate、JPA等。 4. 提供了对分布式事务的支持,可以在多个数据源之间实现跨数据库的事务管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值