zoukankan      html  css  js  c++  java
  • Spring中的@Transactional事务注解

    一、事务特性

    @Transactional注解是用于事务控制的,需要知道事务的ACID特征:即原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

    事务是用来控制数据的ACID特性的,用于保证数据的正确性和完整性。

    @Transactional注解有两种使用方式:

    (1)标注在类上面:当作用于类上时,该类的所有public方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

    (2)标注在方法上面:当作用于方法上时,只有当该方法发生了异常才会进行回滚,其他的方法不受影响。

    在项目中使用,@Transactional(rollbackFor=Exception.class),如果类加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。在@Transactional注解中如果不配置rollbackFor属性,那么事物只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚。


    二、事务传播行为与隔离级别

    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)

    (1)事物传播行为介绍:

    @Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
    @Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不为这个方法开启事务
    @Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕后继续执行老的事务
    @Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常
    @Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
    @Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务那就用事务,如果其他bean没有声明事务,那就不用事务
    

    (2)事物超时设置:

    @Transactional(timeout=30) //默认是30秒
    

    (3)事务隔离级别:

    @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用
    @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
    @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
    @Transactional(isolation = Isolation.SERIALIZABLE):串行化
        
    MYSQL: 默认为REPEATABLE_READ级别
    SQLSERVER: 默认为READ_COMMITTED  
    

    脏读 : 一个事务读取到另一事务未提交的更新数据。
    不可重复读 : 在同一事务中,多次读取同一数据返回的结果有所不同,即后续读取可能读到另一事务已提交的更新数据, 相反, "可重复读"在同一事务中多次
    读取数据时能够保证所读数据一样,即后续读取不能读到另一事务已提交的更新数据。
    幻读 : 一个事务读到另一个事务已提交的insert数据。


    三、spring支持编程式事务管理和声明式事务管理两种方式

    (1)编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
    (2)声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务管理也有两种常用的方式:一种是基于tx和aop名字空间的xml配置文件;另一种是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。
    使用注解形式的方式使用事务需要在xml配置文件中配置如下信息

    <!-- 服务事务管理 -->
    <bean id="demoTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="demoDataSource"/>
    </bean>
     <!-- 启用事务注解 -->
    <tx:annotation-driven transaction-manager="demoTransactionManager"/>
    

    四、需要注意的几点如下

    (1)@Transactional 注解只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能。
    (2)用spring事务管理器,由spring来负责数据库的打开、提交、回滚,默认遇到运行期异常(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的异常时执行回滚;而遇到需要捕获的异常(throw new Exception("注释");)不会回滚,即遇到受检查的异常(就是非运行时抛出的异常,编译器会检查到的异常叫受检异常)时,需要我们指定方式来让事务回滚。如果要想所有异常都回滚,则要加上@Transactional( rollbackFor=Exception.class),
    如果让unchecked异常不回滚: @Transactional(notRollbackFor=RunTimeException.class)。如下代码所示:

    @Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
    public void methodName() {
       throw new Exception("注释");
    }
    @Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚
    public ItimDaoImpl getItemDaoImpl() {
       throw new RuntimeException("注释");
    }
    

    (3)@Transactional 注解应该只被应用到public可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不具有事务功能。
    (4)@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅是一种元数据,能够被可以识别。上面的例子中,其实正是元素的出现开启了事务行为。也就是说要有具体的bean出现时事务才会起作用。
    (5)Spring团队建议在具体的类(或类的方法)上使用@Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别。因此,请接受Spring团队的建议,必须接受啊!


    五、@Transactional注解所具有的属性

    属性 类型 描述
    value String 可选的限定描述符,指定使用的事务管理器
    propagation enum: Propagation 可选的事务传播行为设置
    isolation enum: Isolation 可选的事务隔离级别设置
    readOnly boolean 读写或只读事务,默认读写
    timeout int (in seconds granularity) 事务超时时间设置
    rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组
    rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组
    noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组
    noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组

    六、事务可能导致锁表

    事务有可能导致锁表,从而导致查询操作超时。锁表的原因是多个事务同时操作某一张表。

    mysql事务锁表参考博文: https://blog.csdn.net/wo541075754/article/details/50717842 (mysql事务锁表导致查询超时)

    mysql中主要是注意以下三张表:

    select * from information_schema.INNODB_LOCKS;
    select  * from information_schema.INNODB_LOCK_WAITS;
    select * from information_schema.INNODB_TRX;
    

    参考博文:
    (1) https://www.cnblogs.com/clwydjgs/p/9317849.html (Spring中的@Transactional(rollbackFor = Exception.class)属性详解)
    (2) https://www.cnblogs.com/caoyc/p/5632963.html (事物注解方式: @Transactional)
    (3) https://www.cnblogs.com/jasonboren/p/11361971.html (mysql事务特性)
    (4) https://www.cnblogs.com/jasonboren/p/13366130.html (Java 异常)

  • 相关阅读:
    Linux 压缩解压文件
    六天玩转javascript:javascript变量与表达式(2)
    六天玩转javascript:javascript变量与表达式(1)
    HTML5服务器端推送事件 解决PHP微信墙推送问题
    signalR制作微信墙 开源
    PhpStorm下Laravel代码智能提示
    ubuntu下使用nginx部署Laravel
    PHP微信墙制作,开源
    信鸽推送.NET SDK 开源
    14年总结
  • 原文地址:https://www.cnblogs.com/jasonboren/p/13678237.html
Copyright © 2011-2022 走看看