zoukankan      html  css  js  c++  java
  • 最详细的@Transactional讲解

    spring如何处理事务呢?下面是个伪代码示意:

    	  begin Transactional;
           try{
               //TODO
               commit;
           }catch (Throwable e){
               if(e属于该提交的(即noRollbackFor指定)的异常类型){
                   commit;
               }else {
                   rollback;
               }
           }
    

    1. transactionManager 当在配置文件中有多个TransactionManager,可以用该属性指定使用哪个事务管理器

    如果要配置全局事务管理,参考这篇文章全局性事务控制如何在springboot中配置

    2. propagation 事务的传播行为 ,默认值为REQUIRED

    • Propagation.REQUIRED
      默认传播行为 如果有事务那么加入此事务,没有就新建一个事务
    	/**
    	 * Support a current transaction, create a new one if none exists.
    	 * <p>This is the default setting of a transaction annotation.
    	 */
    
    • Propagation.SUPPORTS
      如果其他bean调用这个方法,在其他bean中声明了事务那么久加入事务,如果其他bean中没有声明事务就不用事务
    	/**
    	 * Support a current transaction, execute non-transactionally if none exists.
    	 * <p>Note: For transaction managers with transaction synchronization,
    	 * PROPAGATION_SUPPORTS is slightly different from no transaction at all,
    	 * as it defines a transaction scope that synchronization will apply for.
    	 * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
    	 * will be shared for the entire specified scope. Note that this depends on
    	 * the actual synchronization configuration of the transaction manager.
    	 */
    
    • Propagation.REQUIRES_NEW
      不管是否存在事务,都创建一个新的事务。如果已经存在一个事务就停止他
    	/**
    	 * Create a new transaction, suspending the current transaction if one exists.
    	 * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
    	 * on all transaction managers. This in particular applies to
    	 * {@link org.springframework.transaction.jta.JtaTransactionManager},
    	 * which requires the {@code javax.transaction.TransactionManager} to be
    	 * made available it to it (which is server-specific in standard Java EE).
    	 * <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
    	 * transaction synchronizations. Existing synchronizations will be suspended
    	 * and resumed appropriately.
    	 */
    
    • Propagation.NOT_SUPPORTED
      不为这个方法开启事务
    	/**
    	 * Do not support a current transaction; rather always execute non-transactionally.
    	 * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
    	 * on all transaction managers. This in particular applies to
    	 * {@link org.springframework.transaction.jta.JtaTransactionManager},
    	 * which requires the {@code javax.transaction.TransactionManager} to be
    	 * made available it to it (which is server-specific in standard Java EE).
    	 * <p>Note that transaction synchronization is <i>not</i> available within a
    	 * {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
    	 * will be suspended and resumed appropriately.
    	 */
    
    • Propagation.MANDATORY
      必须当前存在事务,否则抛出异常
    	/**
    	 * Support a current transaction, throw an exception if none exists.
    	 * Analogous to EJB transaction attribute of the same name.
    	 */
    
    • Propagation.NEVER
      必须当前没有事务,否则抛出异常,与Propagation.MANDATORY相反
    	/**
    	 * Execute non-transactionally, throw an exception if a transaction exists.
    	 */
    
    • Propagation.NESTED
      如果当前存在事务,则在嵌套事务中执行,类似于ROPAGATION_REQUIRED
    	/**
    	 * Execute within a nested transaction if a current transaction exists,
    	 * behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.
    	 * <p>Note: Actual creation of a nested transaction will only work on specific
    	 * transaction managers. Out of the box, this only applies to the JDBC
    	 */
    

    嵌套事务中发生异常会回滚到savePoint,不对主事务之前的操作产生影响,但提交还要依赖主事务的成功。
    在这里插入图片描述

    3. isolation 事务的隔离度 默认值为DEFAULT

    • DEFAULT使用数据库默认的级别
      postgres数据库的默认隔离级别是已提交读 ,MySQL的默认事务隔离级别是可重复读。
    • READ_UNCOMMITTED 未提交读
    	 A constant indicating that dirty reads, non-repeatable reads and phantom reads
    	 * can occur. This level allows a row changed by one transaction to be read by
    	 * another transaction before any changes in that row have been committed
    	 * (a "dirty read"). If any of the changes are rolled back, the second
    	 * transaction will have retrieved an invalid row.
    
    • READ_COMMITTED 已提交读
    	 A constant indicating that dirty reads are prevented; non-repeatable reads
    	 * and phantom reads can occur. This level only prohibits a transaction
    	 * from reading a row with uncommitted changes in it.
    
    • REPEATABLE_READ 可重复读
    		A constant indicating that dirty reads and non-repeatable reads are
    	 * prevented; phantom reads can occur. This level prohibits a transaction
    	 * from reading a row with uncommitted changes in it, and it also prohibits
    	 * the situation where one transaction reads a row, a second transaction
    	 * alters the row, and the first transaction rereads the row, getting
    	 * different values the second time (a "non-repeatable read").
    
    • SERIALIZABLE 串行化
         A constant indicating that dirty reads, non-repeatable reads and phantom
    	 * reads are prevented. This level includes the prohibitions in
    	 * {@code ISOLATION_REPEATABLE_READ} and further prohibits the situation
    	 * where one transaction reads all rows that satisfy a {@code WHERE}
    	 * condition, a second transaction inserts a row that satisfies that
    	 * {@code WHERE} condition, and the first transaction rereads for the
    	 * same condition, retrieving the additional "phantom" row in the second read.
    

    幻读和不可重复读相似容易混淆,幻读值得是相同查询条件的查询行数,另一个事务增加或删除了某行,导致第一个事务两次查询的行数不同。不可重复读指的是另一个事物修改了某行的数据。

    隔离和锁是不同的东西,隔离不是靠锁实现,是根据对数据的监控实现的,相比锁会回滚事务。

    4. timeout 事务的超时时间 默认值为-1. 超时自动回滚

    如果事务超过时间限制还没完成,就会回滚。
    从方法执行开始计算。每个sql执行前检查一次是否超时,方法全部执行完毕后不检查是否超时。即设置事务超时为10秒,即使整个方法耗时20秒也不一定超时。

    假设事务超时时间设置为2秒;假设sql执行时间为1秒;
    如下调用是事务不超时的

    public void testTimeout() throws InterruptedException {  
        System.out.println(System.currentTimeMillis());  
        JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);  
        jdbcTemplate.execute(" update test set hobby = hobby || '1'");  
        System.out.println(System.currentTimeMillis());  
        Thread.sleep(3000L);  
    }  
    

    而如下事务超时是起作用的:

    public void testTimeout() throws InterruptedException {  
        Thread.sleep(3000L);  
        System.out.println(System.currentTimeMillis());  
        JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);  
        jdbcTemplate.execute(" update test set hobby = hobby || '1'");  
        System.out.println(System.currentTimeMillis());  
    }  
    

    參考博客

    5. readOnly 是否为只读事务,默认值为false,即非只读事务

     注意 在只读事务中修改数据库是会报错的!
    

    6. rollbackFor 指定能够触发事务回滚的异常类型 noRollbackFor 指定那些异常类型不回滚事务

  • 相关阅读:
    归并排序模板
    树状数组模板
    KMP模板
    拓扑排序模板
    分布式唯一ID生成算法-雪花算法
    【转载】一起来学Spring Cloud | Eureka Client注册到Eureka Server的秘密
    一起来学Spring Cloud | 第八章:消息总线(Spring Cloud Bus)
    我为什么会成为一个程序猿
    一起来学Spring Cloud | 第七章:分布式配置中心(Spring Cloud Config)
    一起来学Spring Cloud | 第六章:服务网关 ( Zuul)
  • 原文地址:https://www.cnblogs.com/seasail/p/12179363.html
Copyright © 2011-2022 走看看