最详细的@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 指定那些异常类型不回滚事务

posted on 2020-01-11 11:19  spiritt  阅读(1901)  评论(0编辑  收藏  举报