Spring 事务基本概念

前言

本文将用通俗易懂的文字介绍 Spring 事务,主要从面试的角度介绍事务的相关知识,希望能协助初学者快速了解,同时也是为了自己学习的过程做总结。

声明式事务

Spring 事务有两种用法:编程式事务和声明式事务,本文主要介绍声明式事务。所谓声明式事务,就是通过配置的方式,列如通过配置文件(xml)或者注解@Transaction的方式,告知Spring,哪些方法需要Spring帮忙管理事务,然后开发者只用关注业务代码,而事务的事情Spring自动帮我们控制。

简要介绍一下原理:在spring容器加载Bean时,发现有@
EnableTransactionManagement注解,此时会拦截所有bean的创建,扫描看一下bean上是否有@Transaction注解(类、或者父类、或者接口、或者方法中有这个注解都可以),如果有这个注解,spring会通过aop的方式给bean生成代理对象,代理对象中会增加一个拦截器,拦截器会拦截bean中public方法执行,会在方法执行之前启动事务,方法执行完毕之后提交或者回滚事务。

@EnableTransactionManagement

作用于配置类上,用于开启注解事务管理,等同于xml配置方式的 <tx:annotation-driven />

@TransactionEventListener

用于配置事务的监听器,使我们在事务提交和回滚前后可以做一些额外的功能,例如在有些时候保存数据之后,发送消息(列如短信、邮件、微信通知等)来执行其它的操作。

@Transactional

Spring 事务基本概念

@Transactional 注解属性

@Transactional 是Spring 事务的核心注解,可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

虽然@Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 提议不要在接口或者接口方法上使用该注解,由于这只有在使用基于接口的代理时它才会生效。另外, @Transactional注解应该只被应用到 public 方法上,这是由Spring AOP的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

@Transactional五大属性:隔离级别、传播行为、是否只读、事务超时、回滚规则

隔离级别:isolation属性

  1. TransactionDefinition.ISOLATION_DEFAULT:使用数据库默认隔离级别
  2. TransactionDefinition.ISOLATION_READ_UNCOMMITTED:读取未提交数据(会出现脏读,不可重复读) 基本不使用
  3. TransactionDefinition.ISOLATION_READ_COMMITTED:读取已提交数据(会出现不可重复读和幻读)
  4. TransactionDefinition.ISOLATION_REPEATABLE_READ:可重复读(会出现幻读)
  5. TransactionDefinition.ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别,也是最慢的事务隔离级别,由于它一般是通过完全锁定事务相关的数据库表来实现的

传播行为:propagation 属性

  1. TransactionDefinition.TIMEOUT_DEFAULT:使用默认超时的底层事务系统,或者如果不支持超时则没有。
  2. TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
  3. TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  4. TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  5. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  6. TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  7. TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  8. TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

是否只读:readOnly 属性(默认false)

  1. readOnly=true 表明当前事务是只读事务,所注解的方法或类只是读取数据,若增删改会报异常。
  2. readOnly=false 表明当前事务非只读事务,可以进行增加,删除,修改数据。

只读事务与不使用事务的区别?

不使用事务:默认情况下每次查询,查询到的都是其他事物已提交的数据。

只读事务从只读事务开始直到事务结束,整个过程其他事务提交的数据,该事务过程中都忽略。即查询过程中,不会查询到该事物开启之后任何改变的数据,保证了数据的读一致性。

只查询数据需不需要加 @Transactional 注解?

  • 若一个事务里只发出一条select语句,则没有必要启用事务支持,数据库默认支持sql执行期间的读一致性。此时可以不加@Transactional注解。
  • 若一个事务里先后发出了多条select语句。 @Transactional注解表明被申明方法是一个整体事务。多次查询结果不会改变,所以能保证读一致性(可重复读);相反若不加 @Transactional注解,则多条select都是独立的事务在前条select之后,后条select之前,数据被其他事务改变,则该次整体的查询将会出现读数据不一致的现象。此时需要添加@Transactional注解。

事务超时 timeout

timeout 后事务超出指定执行时长后自动终止并回滚。为了使应用程序很好地运行,事务不能运行太长的时间。由于事务可能涉及对后端数据库的锁定,也会占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。

回滚规则 rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName

事务回滚规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,只有未检查异常(RuntimeException和Error类型的异常)会导致事务回滚。而在遇到检查型异常时不会回滚。 但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。

rollbackFor、rollbackForClassName用于设置那些异常需要回滚;noRollbackFor、noRollbackForClassName用于设置那些异常不需要回滚。他们就是在设置事务的回滚规则。

© 版权声明

相关文章

暂无评论

none
暂无评论...