精华内容
下载资源
问答
  • @Transactional 详解

    万次阅读 多人点赞 2018-11-23 16:47:14
    @Transactional 是声明式事务管理 编程中使用的注解 1 .添加位置 1)接口实现类或接口实现方法上,而不是接口类中。 2)访问权限:public 的方法才起作用。@Transactional 注解应该只被应用到 public 方法上,这是...

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。


    @Transactional 是声明式事务管理 编程中使用的注解

    1 .添加位置

    1)接口实现类或接口实现方法上,而不是接口类中。
    2)访问权限:public 的方法才起作用。@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。
    系统设计:将标签放置在需要进行事务管理的方法上,而不是放在所有接口实现类上:只读的接口就不需要事务管理,由于配置了@Transactional就需要AOP拦截及事务的处理,可能影响系统性能。

    3)错误使用:

    1.接口中A、B两个方法,A无@Transactional标签,B有,上层通过A间接调用B,此时事务不生效。
    
    2.接口中异常(运行时异常)被捕获而没有被抛出。
      默认配置下,spring 只有在抛出的异常为运行时 unchecked 异常时才回滚该事务,
      也就是抛出的异常为RuntimeException 的子类(Errors也会导致事务回滚),
      而抛出 checked 异常则不会导致事务回滚 。可通过 @Transactional rollbackFor进行配置。
    
    3.多线程下事务管理因为线程不属于 spring 托管,故线程不能够默认使用 spring 的事务,
      也不能获取spring 注入的 bean 。
      在被 spring 声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。
      一个使用了@Transactional 的方法,如果方法内包含多线程的使用,方法内部出现异常,
      不会回滚线程中调用方法的事务。
    
    


    2.声明式事务管理实现方式:
    基于 tx 和 aop 名字空间的 xml 配置文件

    // 基本配置
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:task="http://www.springframework.org/schema/task" xmlns:jms="http://www.springframework.org/schema/jms"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
                              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
                              http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
                              http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
                              http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
                              http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.1.xsd">
    
    <bean name="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="shardingDataSource"></property>
        </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
    
    // MyBatis 自动参与到 spring 事务管理中,无需额外配置,
    只要 org.mybatis.spring.SqlSessionFactoryBean 引用的数据源与
    DataSourceTransactionManager 引用的数据源一致即可,否则事务管理会不起作用。
    
    // <annotation-driven> 标签的声明,
    是在 Spring 内部启用 @Transactional 来进行事务管理,使用 @Transactional 前需要配置。
    


    3. @Transactional注解
    @Transactional 实质是使用了 JDBC 的事务来进行事务控制的
    @Transactional 基于 Spring 的动态代理的机制
     

    @Transactional 实现原理:
    
    1) 事务开始时,通过AOP机制,生成一个代理connection对象,
       并将其放入 DataSource 实例的某个与 DataSourceTransactionManager 相关的某处容器中。
       在接下来的整个事务中,客户代码都应该使用该 connection 连接数据库,
       执行所有数据库命令。
       [不使用该 connection 连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚]
      (物理连接 connection 逻辑上新建一个会话session;
       DataSource 与 TransactionManager 配置相同的数据源)
    
    2) 事务结束时,回滚在第1步骤中得到的代理 connection 对象上执行的数据库命令,
       然后关闭该代理 connection 对象。
      (事务结束后,回滚操作不会对已执行完毕的SQL操作命令起作用)


    4.声明式事务的管理实现本质:
    事务的两种开启方式:
          显示开启 start transaction | begin,通过 commit | rollback 结束事务
          关闭数据库中自动提交 autocommit set autocommit = 0;MySQL 默认开启自动提交;通过手动提交或执行回滚操作来结束事务


    Spring 关闭数据库中自动提交:在方法执行前关闭自动提交,方法执行完毕后再开启自动提交

     // org.springframework.jdbc.datasource.DataSourceTransactionManager.java 源码实现
     // switch to manual commit if necessary. this is very expensive in some jdbc drivers,
     // so we don't want to do it unnecessarily (for example if we've explicitly
     // configured the connection pool to set it already).
     if (con.getautocommit()) {
         txobject.setmustrestoreautocommit(true);
         if (logger.isdebugenabled()) {
             logger.debug("switching jdbc connection [" + con + "] to manual commit");
         }
         con.setautocommit(false);
     }
     

    问题:

    关闭自动提交后,若事务一直未完成,即未手动执行 commit 或 rollback 时如何处理已经执行过的SQL操作?

    C3P0 默认的策略是回滚任何未提交的事务
    C3P0 是一个开源的JDBC连接池,它实现了数据源和 JNDI 绑定,支持 JDBC3 规范和 JDBC2 的标准扩展。目前使用它的开源项目有 Hibernate,Spring等
    JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互

    -------------------------------------------------------------------------------------------------------------------------------
    5. spring 事务特性
    spring 所有的事务管理策略类都继承自 org.springframework.transaction.PlatformTransactionManager 接口

    public interface PlatformTransactionManager {
      TransactionStatus getTransaction(TransactionDefinition definition)
      throws TransactionException;
      void commit(TransactionStatus status) throws TransactionException;
      void rollback(TransactionStatus status) throws TransactionException;
    }

    事务的隔离级别:是指若干个并发的事务之间的隔离程度

    1. @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读,
     不可重复读) 基本不使用
    
    2. @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
    
    3. @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
    
    4. @Transactional(isolation = Isolation.SERIALIZABLE):串行化

    事务传播行为:如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为

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



    上表字段说明:

    1. value :主要用来指定不同的事务管理器;
       主要用来满足在同一个系统中,存在不同的事务管理器。
       比如在Spring中,声明了两种事务管理器txManager1, txManager2.然后,
       用户可以根据这个参数来根据需要指定特定的txManager.
    
    2. value 适用场景:在一个系统中,需要访问多个数据源或者多个数据库,
       则必然会配置多个事务管理器的
    
    3. REQUIRED_NEW:内部的事务独立运行,在各自的作用域中,可以独立的回滚或者提交;
       而外部的事务将不受内部事务的回滚状态影响。
    
    4. ESTED 的事务,基于单一的事务来管理,提供了多个保存点。
       这种多个保存点的机制允许内部事务的变更触发外部事务的回滚。
       而外部事务在混滚之后,仍能继续进行事务处理,即使部分操作已经被混滚。 
       由于这个设置基于 JDBC 的保存点,所以只能工作在 JDB C的机制。
    
    5. rollbackFor:让受检查异常回滚;即让本来不应该回滚的进行回滚操作。
    
    6. noRollbackFor:忽略非检查异常;即让本来应该回滚的不进行回滚操作。
    
    

    6.其他:

    1. 事务方法的嵌套调用会产生事务传播。
    2. spring 的事务管理是线程安全的
    3. 父类的声明的 @Transactional 会对子类的所有方法进行事务增强;
       子类覆盖重写父类方式可覆盖其 @Transactional 中的声明配置。
    
    4. 类名上方使用 @Transactional,类中方法可通过属性配置来覆盖类上的 @Transactional 配置;
       比如:类上配置全局是可读写,可在某个方法上改为只读。

    如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。 
    如果不想终止,则必须捕获所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。


    非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。如IOException、SQLException等以及用户自定义的Exception异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch并处理,否则程序就不能编译通过。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。


    --------------------- 

    转自:https://blog.csdn.net/mingyundezuoan/article/details/79017659 

    https://www.cnblogs.com/clwydjgs/p/9317849.html

    展开全文
  • Transactional

    2018-10-16 15:01:04
    Transactional @Transactional 加于private方法, 无效 @Transactional 加于未加入接口的public方法, 再通过普通接口方法调用, 无效 @Transactional 加于接口方法, 无论下面调用的是private或public方法, 都有效 ...

    Transactional

    @Transactional 加于private方法, 无效

    @Transactional 加于未加入接口的public方法, 再通过普通接口方法调用, 无效

    @Transactional 加于接口方法, 无论下面调用的是private或public方法, 都有效

    @Transactional 加于接口方法后, 被本类普通接口方法直接调用, 无效

    @Transactional 加于接口方法后, 被本类普通接口方法通过接口调用, 有效

    @Transactional 加于接口方法后, 被它类的接口方法调用, 有效

    @Transactional 加于接口方法后, 被它类的私有方法调用后, 有效

    手动事物回滚
    @Transactional(rollbackFor = Exception.class)
     
    public Integer compute(ProductInfo p){ 
     
            try{
     
                ...
     
            }catch(Exception e){
     
                 e.printStackTrace();
     
                 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
     
                 return 0;
     
            }
     
    }
    

    事务传播模式

    Propagation枚举了多种事务传播模式,部分列举如下:

    1. REQUIRED(默认模式):业务方法需要在一个容器里运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。
    2. NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。
    3. REQUIRESNEW:不管是否存在事务,该方法总汇为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。
    4. MANDATORY:该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。
    5. SUPPORTS:该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。
    6. NEVER:该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。
    7. NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。

    解决Transactional注解不回滚

    1. 检查你方法是不是public的。
    2. 你的异常类型是不是unchecked异常。
      如果我想check异常也想回滚怎么办,注解上面写明异常类型即可。
      @Transactional(rollbackFor=Exception.class)
      类似的还有norollbackFor,自定义不回滚的异常。
    3. 数据库引擎要支持事务,如果是mysql,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的。
    4. 是否开启了对注解的解析
      <tx:annotation-driven transaction-manager=“transactionManager” proxy-target-class=“true”/>
    5. spring是否扫描到你这个包,如下是扫描到org.test下面的包
      <context:component-scan base-package=“org.test” ></context:component-scan>
    展开全文
  • @Transactional的使用

    万次阅读 多人点赞 2019-10-16 22:26:54
    @Transactional的使用 1.Spring事务的原理 Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑...

    1.Spring事务的原理

    Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件中做相关的事务规则声明,另一种是基于@Transactional 注解的方式。
    使用@Transactional的相比传统的我们需要手动开启事务,然后提交事务来说。它提供如下方便

    • 根据你的配置,设置是否自动开启事务
    • 自动提交事务或者遇到异常自动回滚

    声明式事务(@Transactional)基本原理如下:

    1. 配置文件开启注解驱动,在相关的类和方法上通过注解@Transactional标识。
    2. spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,并根据@Transaction的相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)。
    3. 真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

    2.@Transactional使用注意点

    1. @Transactional注解只能在抛出RuntimeException或者Error时才会触发事务的回滚,常见的非RuntimeException是不会触发事务的回滚的。但是我们平时做业务处理时,需要捕获异常,所以可以手动抛出RuntimeException异常或者添加rollbackFor = Exception.class(也可以指定相应异常)
    /*
     * 捕获异常时,要想使事务生效,需要手动抛出RuntimeException异常或者添加rollbackFor = Exception.class
    */
    @Override
    @Transactional
    public Long addBook(Book book) {
        Long result = null;
        try {
            result = bookDao.addBook(book);
            int i = 1/0;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
        return result;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addBook(Book book) {
        Long result = null;
        try {
            result = bookDao.addBook(book);
            int i = 1/0;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
        return result;
    }
    
    1. 只有public修饰的方法才会生效
    2. 方法内自调用导致的事务不生效

    如下几种情况:

    /*
    * 情况一:都有事务注解,异常在子方法出现,事务生效
    */
    @Override
    @Transactional
    public Long addBook(Book book) {
        Long result = add(book);
        return result;
    }
    
    @Transactional
    public Long add(Book book){
        Long result =  bookDao.addBook(book);
        int i = 1/0;
        return result;
    }
    
    /*
    * 情况二:都有事务注解,异常在主方法出现,事务生效
    */
    @Override
    @Transactional
    public Long addBook(Book book) {
        Long result = add(book);
        int i = 1/0;
        return result;
    }
    
    @Transactional
    public Long add(Book book){
        Long result =  bookDao.addBook(book);
        return result;
    }
    
    /*
    * 情况三:只有主方法有事务注解,异常在子方法出现,事务生效
    */
    @Override
    @Transactional
    public Long addBook(Book book) {
        Long result = add(book);
        return result;
    }
    
    public Long add(Book book){
        Long result =  bookDao.addBook(book);
        int i = 1/0;
        return result;
    }
    
    /*
    * 情况四:只有主方法有事务注解,异常在主方法出现,事务生效
    */
    @Override
    @Transactional
    public Long addBook(Book book) {
        Long result = add(book);
        int i = 1/0;
        return result;
    }
    
    public Long add(Book book){
        Long result =  bookDao.addBook(book);
        return result;
    }
    
    /*
    * 情况五:只有子方法有事务注解,异常在子方法出现,事务不生效
    */
    @Override
    public Long addBook(Book book) {
        Long result = add(book);
        return result;
    }
    
    @Transactional
    public Long add(Book book){
        Long result =  bookDao.addBook(book);
        int i = 1/0;
        return result;
    }
    

    结论:当无事务方法调用有事务的方法时事务不会生效,而主方法有事务去调用其他方法,无论被调用的方法有无事务,且是否出现异常(有异常需要能够抛出不被捕获),都触发事务。

    展开全文
  • @Transactional

    万次阅读 多人点赞 2018-01-09 21:28:33
    @Transactional 事务管理的目的 在出现异常的情况下,保证数据的一致性;数据提交操作回滚至异常发生前的状态 事务管理的方式: Spring(Spring Framework 提供对事务管理的抽象接口...

    @Transactional


    概述

    • @Transactional 是声明式事务管理 编程中使用的注解

    • 添加位置

      • 接口实现类或接口实现方法上,而不是接口类中
    • 访问权限:public 的方法才起作用

      • @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解
    • 系统设计:将标签放置在需要进行事务管理的方法上,而不是不假思索的放置在接口实现类上( 接口中所有方法都需要进行事务管理,但其实并不需要,如只读的接口就不需要事务管理,但是 由于配置了@Transactional就需要AOP拦截及事务的处理,影响系统性能)

    • 方法上注解属性会覆盖类注解上的相同属性,当接口与接口中方法上同时带有@Transactional注解时

    • 错误使用:

      • 接口中A、B两个方法,A无@Transactional标签,B有,上层通过A间接调用B,此时事务不生效
      • 接口中异常(运行时异常)被捕获而没有被抛出
        • 默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚
        • 可通过 @Transactional rollbackFor进行配置
    • 多线程下事务管理

      • 因为线程不属于spring托管,故线程不能够默认使用spring的事务,也不能获取spring注入的bean
      • 在被spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制
        • 一个使用了@Transactional 的方法,如果方法内包含多线程的使用,方法内部出现异常,不会回滚线程中调用方法的事务

    声明式事务管理实现方式:

    • 基于tx和aop名字空间的xml配置文件
    // 基本配置
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:task="http://www.springframework.org/schema/task" xmlns:jms="http://www.springframework.org/schema/jms"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
    						  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    						  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
    						  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
    						  http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
    						  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
    						  http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.1.xsd">
    
    <bean name="transactionManager"
    		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="shardingDataSource"></property>
    	</bean>
    
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
    
    // MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用
    // <annotation-driven>标签的声明,则是在Spring内部启用@Transactional来进行事务管理,使用 @Transactional 前需要配置
    
    • 基于@Transactional注解
      @Transactional实质是使用了JDBC的事务来进行事务控制的
      @Transactional基于Spring的动态代理的机制
    • @Transactional实现原理
    • 1)事务开始时,通过AOP机制,生成一个代理connection对象,并将其放入DataSource实例的某个与DataSourceTransactionManager相关的某处容器中。在接下来的整个事务中,客户代码都应该使用该connection连接数据库,执行所有数据库命令[不使用该connection连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚](物理连接connection逻辑上新建一个会话session;DataSource与TransactionManager配置相同的数据源)
    • 2)事务结束时,回滚在第1步骤中得到的代理connection对象上执行的数据库命令,然后关闭该代理connection对象(事务结束后,回滚操作不会对已执行完毕的SQL操作命令起作用)

    声明式事务的管理实现本质:

    • 事务的两种开启方式
      • 显示开启start transaction | begin,通过 commit | rollback 结束事务
      • 关闭数据库中自动提交 autocommit set autocommit = 0;MySQL 默认开启自动提交;通过手动提交或执行回滚操作来结束事务
    • Spring 关闭数据库中自动提交:在方法执行前关闭自动提交,方法执行完毕后再开启自动提交
     // org.springframework.jdbc.datasource.DataSourceTransactionManager.java 源码实现
     // switch to manual commit if necessary. this is very expensive in some jdbc drivers,
     // so we don't want to do it unnecessarily (for example if we've explicitly
     // configured the connection pool to set it already).
     if (con.getautocommit()) {
         txobject.setmustrestoreautocommit(true);
         if (logger.isdebugenabled()) {
             logger.debug("switching jdbc connection [" + con + "] to manual commit");
         }
         con.setautocommit(false);
     }
     
    
    • 问题:

    • 关闭自动提交后,若事务一直未完成,即未手动执行 commit 或 rollback 时如何处理已经执行过的SQL操作?

      • C3P0默认的策略是回滚任何未提交的事务
      • C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等
      • JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互

    spring事务特性

    • spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口
    public interface PlatformTransactionManager {
      TransactionStatus getTransaction(TransactionDefinition definition)
      throws TransactionException;
      void commit(TransactionStatus status) throws TransactionException;
      void rollback(TransactionStatus status) throws TransactionException;
    }
    
    • 事务的隔离级别:是指若干个并发
      的事务之间的隔离程度

    • @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用

    • @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)

    • @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)

    • @Transactional(isolation = Isolation.SERIALIZABLE):串行化

    • 事务传播行为:如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为

      • TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
      • TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
      • TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
      • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
      • TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
      • TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
      • TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

    @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 不会导致事务回滚的异常类名字数组

    说明:

    • value :主要用来指定不同的事务管理器;主要用来满足在同一个系统中,存在不同的事务管理器。比如在Spring中,声明了两种事务管理器txManager1, txManager2.然后,用户可以根据这个参数来根据需要指定特定的txManager.
    • value 适用场景:在一个系统中,需要访问多个数据源或者多个数据库,则必然会配置多个事务管理器的
    • REQUIRED_NEW和NESTED两种不同的传播机制的区别
    • REQUIRED_NEW:内部的事务独立运行,在各自的作用域中,可以独立的回滚或者提交;而外部的事务将不受内部事务的回滚状态影响
    • ESTED的事务,基于单一的事务来管理,提供了多个保存点。这种多个保存点的机制允许内部事务的变更触发外部事务的回滚。而外部事务在混滚之后,仍能继续进行事务处理,即使部分操作已经被混滚。 由于这个设置基于JDBC的保存点,所以只能工作在JDBC的机制
    • rollbackFor : 让受检查异常回滚;即让本来不应该回滚的进行回滚操作
    • noRollbackFor :忽略非检查异常;即让本来应该回滚的不进行回滚操作

    嵌套事务

    • 带有事务的方法调用其他事务的方法,此时执行的情况取决配置的事务的传播属性

      • PROPAGATION_REQUIRES_NEW :
        • 启动一个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.
      • PROPAGATION_NESTED :
        • 如果外部事务 commit, 嵌套事务也会被 commit;如果外部事务 roll back, 嵌套事务也会被 roll back 。
        • 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 嵌套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交
    • 关于Spring的事务Transactional,锁同步,并发线程


    spring事务回滚规则

    • 指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常
      spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务
    • 默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。
    • 用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException(“注释”);)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception(“注释”);)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)

    注意事项:

    • @Transactional 使用位置 类上方、方法上方
      Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效
      当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

    • 方法的访问权限为 public
      @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常

    • 默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰
      例如一:同一个类中方法,A方法未使用此标签,B使用了,C未使用,A 调用 B , B 调用 C ;则外部调用A之后,B的事务是不会起作用的
      例如二:若是有上层(按照 Controller层、Service层、DAO层的顺序)由Action 调用 Service 直接调用,发生异常会发生回滚;若间接调用,Action 调用 Service 中 的A 方法,A无@Transactional 注解,B有,A调用B,B的注解无效


    其他

    • 事务方法的嵌套调用会产生事务传播
    • spring 的事务管理是线程安全的
    • 父类的声明的@Transactional会对子类的所有方法进行事务增强;子类覆盖重写父类方式可覆盖其@Transactional中的声明配置
    • 类名上方使用@Transactional,类中方法可通过属性配置覆盖类上的@Transactional配置;比如:类上配置全局是可读写,可在某个方法上改为只读

    源码阅读


    参考资料


    多线程事务管理

    • 描述

      • 因为线程不属于spring托管,故线程不能够默认使用spring的事务,也不能获取spring注入的bean
      • 在被spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制
    • 解决

      • 如果方法中调用多线程
        • 方法主题的事务不会传递到线程中
        • 线程中可以单独调用Service接口,接口的实现方法使用@Transactional,保证线程内部的事务
      • 多线程实现的方法
        • 使用异步注解@Async的方法上再加上注解@Transactional,保证新线程调用的方法是有事务管理的
    • 原理

      • Spring中事务信息存储在ThreadLocal变量中,变量是某个线程上进行的事务所特有的(这些变量对于其他线程中发生的事务来讲是不可见的,无关的)
      • 单线程的情况下,一个事务会在层级式调用的Spring组件之间传播
      • 在@Transactional注解的服务方法会产生一个新的线程的情况下,事务是不会从调用者线程传播到新建线程的
    • 参考资料

    展开全文
  • grails 事务 Transactional

    千次阅读 2015-09-15 17:13:45
    Transactional
  • Java的@Transactional事务回滚

    万次阅读 2019-12-10 13:26:17
    在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否...
  • 高清的英文版Transactional Information Systems,带标签。
  • Transactional 注解

    2018-04-08 15:25:05
    @Transactional 当标于类前时, 标示类中所有方法都进行事物处理
  • Spring是如何管理事务的之@Transactional注解详解

    万次阅读 多人点赞 2018-08-02 15:19:51
    前两天在工作中忙的焦头烂额,涉及到@Transactional对于事务的控制,便仔细研究了一下,颇有所获,花费好了几天测试整理,今天才发表出来,希望看到博客的老铁们能有所获吧。话不多说直奔正题。 先简单介绍一下...
  • oracle Transactional

    2019-07-01 09:49:00
    从shutdown transactional命令发布起, 禁止建立任何新的oracle连接。 从shutdown transactional命令发布起,禁止启动任何新的事务。 一旦数据库上所有的活动事务执行完毕, 所有的客户连接将被断开。 完成事务...
  • 基于SSM架构的项目,在服务层方法添加了@Transactional注解,applicationContext开启了注解: &amp;lt;!-- 事物管理器 --&amp;gt; &amp;lt;bean id=&quot;transactionManager&quot; class=...
  • Transactional Memory

    2008-10-05 19:51:24
    Transactional Memory的入门书
  • Transactional注解

    2018-03-27 10:47:19
    这几天在项目里面发现我使用@Transactional注解事务之后,抛了异常居然不回滚。后来终于找到了原因。 如果你也出现了这种情况,可以从下面开始排查。 一、特性 先来了解一下@Transactional注解事务的特性吧,可以...
  • 一、@Transactional 简介? @Transactional 是声明式事务管理使用@Transactional的相比传统的我们需要手动开启事务,然后提交事务来说。它提供如下方便根据你的配置,设置是否自动开启事务自动提交事务或者遇到异常...
  • spring @Transactional

    2019-01-16 11:11:08
    1,加上@Transactional(rollbackFor=Exception.class) 1 让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class) 2 让unchecked例外不回滚: @Transactional(notRollbackFor=...
  • 事务@Transactional

    2019-11-28 17:31:51
    事物注解方式: @Transactional 当标于类前时, 标示类中所有方法都进行事物处理 , 例子: @Transactional public class TestServiceBean implements TestService {} 当类中某些方法不需要事物时: 1 @...
  • 主要介绍了Spring @Transactional工作原理详解,具有一定借鉴价值,需要的朋友可以参考下。
  • Spring Transactional

    2018-05-30 16:30:00
    Spring Transactional 1.默认spring事务只在发生未被捕获的 RuntimeException 时才回滚。 spring aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常...
  • SpringBoot@Transactional

    2020-04-07 16:28:21
    SpringBoot项目会自动配置一个 DataSourceTransactionManager,所以我们只需在方法(或者类)加上 @Transactional 注解,就自动纳入 Spring 的事务管理了 使用@Transactional事务几点注意 1.不要在接口上声明@...
  • 注解@Transactional

    2021-04-09 10:43:38
    @Transactional注解中常用参数说明 readOnly 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true) rollbackFor 该属性用于设置需要...
  • @Transactional注解

    2019-12-22 16:50:38
    @Transactional注解 一.事物传播行为介绍: @Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)  @Transactional(propagation=Propagation.NOT_SUPPORTED...
  • 主要介绍了Spring中@Transactional用法详细介绍的相关资料,需要的朋友可以参考下
  • 主要介绍了spring的@Transactional注解用法解读,具有一定借鉴价值,需要的朋友可以参考下

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 103,321
精华内容 41,328
关键字:

transactional