传播性

事务传播行为是为了解决业务层方法之间互相调用的事务问题,当一个事务方法被另一个事务方法调用时,事务该以何种状态存在?例如新方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行,等等,这些规则就涉及到事务的传播性。

关于事务的传播性,Spring 主要定义了如下几种:

 REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),\
 SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),\
 MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),\
 REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),\
 NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),\
 NEVER(TransactionDefinition.PROPAGATION_NEVER),\
 NESTED(TransactionDefinition.PROPAGATION_NESTED);\
 private final int value;\
 Propagation(int value) { this.value = value; }\
 public int value() { return this.value; }\
}

具体含义如下:

传播性 描述
REQUIRED 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务
SUPPORTS 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
MANDATORY 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
REQUIRES_NEW 创建一个新的事务,如果当前存在事务,则把当前事务挂起
NOT_SUPPORTED 以非事务方式运行,如果当前存在事务,则把当前事务挂起
NEVER 以非事务方式运行,如果当前存在事务,则抛出异常
NESTED 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 TransactionDefinition.PROPAGATION_REQUIRED

一共是七种传播性,具体配置也简单:

TransactionTemplate中的配置

transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

PlatformTransactionManager中的配置

public void update2() {\
    //创建事务的默认配置\
    DefaultTransactionDefinition definition = new DefaultTransactionDefinition();\
    definition.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);\
    definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);\
    TransactionStatus status = platformTransactionManager.getTransaction(definition);\
    try {\
        jdbcTemplate.update("update account set money = ? where username=?;", 999, "zhangsan");\
        int i = 1 / 0;\
        //提交事务\
        platformTransactionManager.commit(status);\
    } catch (DataAccessException e) {\
          e.printStackTrace();\
        //回滚\
        platformTransactionManager.rollback(status);\
    }\
}

声明式事务的配置(XML)

<tx:advice id="txAdvice" transaction-manager="transactionManager">\
    <tx:attributes>\
        <!--以 add 开始的方法,添加事务-->\
        <tx:method name="add*"/>\
        <tx:method name="insert*" isolation="SERIALIZABLE" propagation="REQUIRED"/>\
    </tx:attributes>\
</tx:advice>

声明式事务的配置(Java)

@Transactional(noRollbackFor = ArithmeticException.class,propagation = Propagation.REQUIRED)\
public void update4() {\
    jdbcTemplate.update("update account set money = ? where username=?;", 998, "lisi");\
    int i = 1 / 0;\
}

用就是这么来用,至于七种传播的具体含义,和大家一个一个说。

REQUIRED 表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

例如我有如下一段代码:

@Service\
public class AccountService {\
    @Autowired\
    JdbcTemplate jdbcTemplate;\
    @Transactional\
    public void handle1() {\
        jdbcTemplate.update("update user set money = ? where id=?;", 1, 2);\
    }\
}\
@Service\
public class AccountService2 {\
    @Autowired\
    JdbcTemplate jdbcTemplate;\
    @Autowired\
    AccountService accountService;\
    public void handle2() {\
        jdbcTemplate.update("update user set money = ? where username=?;", 1, "zhangsan");\
        accountService.handle1();\
    }\
}

我在 handle2 方法中调用 handle1。

那么:

  1. 如果 handle2 方法本身是有事务的,则 handle1 方法就会加入到 handle2 方法所在的事务中,这样两个方法将处于同一个事务中,一起成功或者一起失败(不管是 handle2 还是 handle1 谁抛异常,都会导致整体回滚)。
  2. 如果 handle2 方法本身是没有事务的,则 handle1 方法就会自己开启一个新的事务,自己玩。

举一个简单的例子:handle2 方法有事务,handle1 方法也有事务(小伙伴们根据前面的讲解自行配置事务),项目打印出来的事务日志如下:

o.s.jdbc.support.JdbcTransactionManager  : Creating new transaction with name [org.javaboy.spring_tran02.AccountService2.handle2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT\
o.s.jdbc.support.JdbcTransactionManager  : Acquired Connection [HikariProxyConnection@875256468 wrapping com.mysql.cj.jdbc.ConnectionImpl@9753d50] for JDBC transaction\
o.s.jdbc.support.JdbcTransactionManager  : Switching JDBC Connection [HikariProxyConnection@875256468 wrapping com.mysql.cj.jdbc.ConnectionImpl@9753d50] to manual commit\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where username=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Participating in existing transaction\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where id=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Initiating transaction commit\
o.s.jdbc.support.JdbcTransactionManager  : Committing JDBC transaction on Connection [HikariProxyConnection@875256468 wrapping com.mysql.cj.jdbc.ConnectionImpl@9753d50]\
o.s.jdbc.support.JdbcTransactionManager  : Releasing JDBC Connection [HikariProxyConnection@875256468 wrapping com.mysql.cj.jdbc.ConnectionImpl@9753d50] after transaction

从日志中可以看到,前前后后一共就开启了一个事务,日志中有这么一句:

Participating in existing transaction

这个就说明 handle1 方法没有自己开启事务,而是加入到 handle2 方法的事务中了。

5.2.2 REQUIRES_NEW

REQUIRES_NEW 表示创建一个新的事务,如果当前存在事务,则把当前事务挂起。换言之,不管外部方法是否有事务,REQUIRES_NEW 都会开启自己的事务。

这块松哥要多说两句,有的小伙伴可能觉得 REQUIRES_NEW 和 REQUIRED 太像了,似乎没啥区别。其实你要是单纯看最终回滚效果,可能确实看不到啥区别。但是,大家注意松哥上面的加粗,在 REQUIRES_NEW 中可能会同时存在两个事务,外部方法的事务被挂起,内部方法的事务独自运行,而在 REQUIRED 中则不会出现这种情况,如果内外部方法传播性都是 REQUIRED,那么最终也只是一个事务。

还是上面那个例子,假设 handle1 和 handle2 方法都有事务,handle2 方法的事务传播性是 REQUIRED,而 handle1 方法的事务传播性是 REQUIRES_NEW,那么最终打印出来的事务日志如下:

o.s.jdbc.support.JdbcTransactionManager  : Creating new transaction with name [org.javaboy.spring_tran02.AccountService2.handle2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT\
o.s.jdbc.support.JdbcTransactionManager  : Acquired Connection [HikariProxyConnection@422278016 wrapping com.mysql.cj.jdbc.ConnectionImpl@732405c2] for JDBC transaction\
o.s.jdbc.support.JdbcTransactionManager  : Switching JDBC Connection [HikariProxyConnection@422278016 wrapping com.mysql.cj.jdbc.ConnectionImpl@732405c2] to manual commit\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where username=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Suspending current transaction, creating new transaction with name [org.javaboy.spring_tran02.AccountService.handle1]\
o.s.jdbc.support.JdbcTransactionManager  : Acquired Connection [HikariProxyConnection@247691344 wrapping com.mysql.cj.jdbc.ConnectionImpl@14ad4b95] for JDBC transaction\
com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@14ad4b95\
o.s.jdbc.support.JdbcTransactionManager  : Switching JDBC Connection [HikariProxyConnection@247691344 wrapping com.mysql.cj.jdbc.ConnectionImpl@14ad4b95] to manual commit\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where id=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Initiating transaction commit\
o.s.jdbc.support.JdbcTransactionManager  : Committing JDBC transaction on Connection [HikariProxyConnection@247691344 wrapping com.mysql.cj.jdbc.ConnectionImpl@14ad4b95]\
o.s.jdbc.support.JdbcTransactionManager  : Releasing JDBC Connection [HikariProxyConnection@247691344 wrapping com.mysql.cj.jdbc.ConnectionImpl@14ad4b95] after transaction\
o.s.jdbc.support.JdbcTransactionManager  : Resuming suspended transaction after completion of inner transaction\
o.s.jdbc.support.JdbcTransactionManager  : Initiating transaction commit\
o.s.jdbc.support.JdbcTransactionManager  : Committing JDBC transaction on Connection [HikariProxyConnection@422278016 wrapping com.mysql.cj.jdbc.ConnectionImpl@732405c2]\
o.s.jdbc.support.JdbcTransactionManager  : Releasing JDBC Connection [HikariProxyConnection@422278016 wrapping com.mysql.cj.jdbc.ConnectionImpl@732405c2] after transaction

分析这段日志我们可以看到:

  1. 首先为 handle2 方法开启了一个事务。
  2. 执行完 handle2 方法的 SQL 之后,事务被刮起(Suspending)。
  3. 为 handle1 方法开启了一个新的事务。
  4. 执行 handle1 方法的 SQL。
  5. 提交 handle1 方法的事务。
  6. 恢复被挂起的事务(Resuming)。
  7. 提交 handle2 方法的事务。

从这段日志中大家可以非常明确的看到 REQUIRES_NEW 和 REQUIRED 的区别。

松哥再来简单总结下(假设 handle1 方法的事务传播性是 REQUIRES_NEW):

  1. 如果 handle2 方法没有事务,handle1 方法自己开启一个事务自己玩。
  2. 如果 handle2 方法有事务,handle1 方法还是会开启一个事务。此时,如果 handle2 发生了异常进行回滚,并不会导致 handle1 方法回滚,因为 handle1 方法是独立的事务;如果 handle1 方法发生了异常导致回滚,并且 handle1 方法的异常没有被捕获处理传到了 handle2 方法中,那么也会导致 handle2 方法回滚。

    这个地方小伙伴们要稍微注意一下,我们测试的时候,由于是两个更新 SQL,如果更新的查询字段不是索引字段,那么 InnoDB 将使用表锁,这样就会发生死锁(handle2 方法执行时开启表锁,导致 handle1 方法陷入等待中,而必须 handle1 方法执行完,handle2 才能释放锁)。所以,在上面的测试中,我们要将 username 字段设置为索引字段,这样默认就使用行锁了。

5.2.3 NESTED

NESTED 表示如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 TransactionDefinition.PROPAGATION_REQUIRED。

假设 handle2 方法有事务,handle1 方法也有事务且传播性为 NESTED,那么最终执行的事务日志如下:

o.s.jdbc.support.JdbcTransactionManager  : Creating new transaction with name [org.javaboy.demo.AccountService2.handle2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT\
o.s.jdbc.support.JdbcTransactionManager  : Acquired Connection [HikariProxyConnection@2025689131 wrapping com.mysql.cj.jdbc.ConnectionImpl@2ed3628e] for JDBC transaction\
o.s.jdbc.support.JdbcTransactionManager  : Switching JDBC Connection [HikariProxyConnection@2025689131 wrapping com.mysql.cj.jdbc.ConnectionImpl@2ed3628e] to manual commit\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where username=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Creating nested transaction with name [org.javaboy.demo.AccountService.handle1]\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where id=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Releasing transaction savepoint\
o.s.jdbc.support.JdbcTransactionManager  : Initiating transaction commit\
o.s.jdbc.support.JdbcTransactionManager  : Committing JDBC transaction on Connection [HikariProxyConnection@2025689131 wrapping com.mysql.cj.jdbc.ConnectionImpl@2ed3628e]\
o.s.jdbc.support.JdbcTransactionManager  : Releasing JDBC Connection [HikariProxyConnection@2025689131 wrapping com.mysql.cj.jdbc.ConnectionImpl@2ed3628e] after transaction

关键一句在 Creating nested transaction

此时,NESTED 修饰的内部方法(handle1)属于外部事务的子事务,外部主事务回滚的话,子事务也会回滚,而内部子事务可以单独回滚而不影响外部主事务和其他子事务(需要处理掉内部子事务的异常)。

5.2.4 MANDATORY

MANDATORY 表示如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

这个好理解,我举两个例子:

假设 handle2 方法有事务,handle1 方法也有事务且传播性为 MANDATORY,那么最终执行的事务日志如下:

o.s.jdbc.support.JdbcTransactionManager  : Creating new transaction with name [org.javaboy.demo.AccountService2.handle2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT\
o.s.jdbc.support.JdbcTransactionManager  : Acquired Connection [HikariProxyConnection@768820610 wrapping com.mysql.cj.jdbc.ConnectionImpl@14840df2] for JDBC transaction\
o.s.jdbc.support.JdbcTransactionManager  : Switching JDBC Connection [HikariProxyConnection@768820610 wrapping com.mysql.cj.jdbc.ConnectionImpl@14840df2] to manual commit\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where username=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Participating in existing transaction\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where id=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Initiating transaction commit\
o.s.jdbc.support.JdbcTransactionManager  : Committing JDBC transaction on Connection [HikariProxyConnection@768820610 wrapping com.mysql.cj.jdbc.ConnectionImpl@14840df2]\
o.s.jdbc.support.JdbcTransactionManager  : Releasing JDBC Connection [HikariProxyConnection@768820610 wrapping com.mysql.cj.jdbc.ConnectionImpl@14840df2] after transaction

从这段日志可以看出:

  1. 首先给 handle2 方法开启事务。
  2. 执行 handle2 方法的 SQL。
  3. handle1 方法加入到已经存在的事务中。
  4. 执行 handle1 方法的 SQL。
  5. 提交事务。

假设 handle2 方法无事务,handle1 方法有事务且传播性为 MANDATORY,那么最终执行时会抛出如下异常:

No existing transaction found for transaction marked with propagation 'mandatory'

由于没有已经存在的事务,所以出错了。

5.2.5 SUPPORTS

SUPPORTS 表示如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

这个也简单,举两个例子大家就明白了。

假设 handle2 方法有事务,handle1 方法也有事务且传播性为 SUPPORTS,那么最终事务执行日志如下:

o.s.jdbc.support.JdbcTransactionManager  : Creating new transaction with name [org.javaboy.demo.AccountService2.handle2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT\
o.s.jdbc.support.JdbcTransactionManager  : Acquired Connection [HikariProxyConnection@1780573324 wrapping com.mysql.cj.jdbc.ConnectionImpl@44eafcbc] for JDBC transaction\
o.s.jdbc.support.JdbcTransactionManager  : Switching JDBC Connection [HikariProxyConnection@1780573324 wrapping com.mysql.cj.jdbc.ConnectionImpl@44eafcbc] to manual commit\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where username=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Participating in existing transaction\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where id=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Initiating transaction commit\
o.s.jdbc.support.JdbcTransactionManager  : Committing JDBC transaction on Connection [HikariProxyConnection@1780573324 wrapping com.mysql.cj.jdbc.ConnectionImpl@44eafcbc]\
o.s.jdbc.support.JdbcTransactionManager  : Releasing JDBC Connection [HikariProxyConnection@1780573324 wrapping com.mysql.cj.jdbc.ConnectionImpl@44eafcbc] after transaction

这段日志很简单,没啥好说的,认准 Participating in existing transaction 表示加入到已经存在的事务中即可。

假设 handle2 方法无事务,handle1 方法有事务且传播性为 SUPPORTS,这个最终就不会开启事务了,也没有相关日志。

5.2.6 NOT_SUPPORTED

NOT_SUPPORTED 表示以非事务方式运行,如果当前存在事务,则把当前事务挂起。

假设 handle2 方法有事务,handle1 方法也有事务且传播性为 NOT_SUPPORTED,那么最终事务执行日志如下:

o.s.jdbc.support.JdbcTransactionManager  : Creating new transaction with name [org.javaboy.demo.AccountService2.handle2]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT\
o.s.jdbc.support.JdbcTransactionManager  : Acquired Connection [HikariProxyConnection@1365886554 wrapping com.mysql.cj.jdbc.ConnectionImpl@3198938b] for JDBC transaction\
o.s.jdbc.support.JdbcTransactionManager  : Switching JDBC Connection [HikariProxyConnection@1365886554 wrapping com.mysql.cj.jdbc.ConnectionImpl@3198938b] to manual commit\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where username=?;]\
o.s.jdbc.support.JdbcTransactionManager  : Suspending current transaction\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update\
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update user set money = ? where id=?;]\
o.s.jdbc.datasource.DataSourceUtils      : Fetching JDBC Connection from DataSource\
o.s.jdbc.support.JdbcTransactionManager  : Resuming suspended transaction after completion of inner transaction\
o.s.jdbc.support.JdbcTransactionManager  : Initiating transaction commit\
o.s.jdbc.support.JdbcTransactionManager  : Committing JDBC transaction on Connection [HikariProxyConnection@1365886554 wrapping com.mysql.cj.jdbc.ConnectionImpl@3198938b]\
o.s.jdbc.support.JdbcTransactionManager  : Releasing JDBC Connection [HikariProxyConnection@1365886554 wrapping com.mysql.cj.jdbc.ConnectionImpl@3198938b] after transaction

这段日志大家认准这两句就行了 :Suspending current transaction 表示挂起当前事务;Resuming suspended transaction 表示恢复挂起的事务。

5.2.7 NEVER

NEVER 表示以非事务方式运行,如果当前存在事务,则抛出异常。

假设 handle2 方法有事务,handle1 方法也有事务且传播性为 NEVER,那么最终会抛出如下异常:

Existing transaction found for transaction marked with propagation 'never'

5.3 回滚规则

默认情况下,事务只有遇到运行期异常(RuntimeException 的子类)以及 Error 时才会回滚,在遇到检查型(Checked Exception)异常时不会回滚。

像 1/0,空指针这些是 RuntimeException,而 IOException 则算是 Checked Exception,换言之,默认情况下,如果发生 IOException 并不会导致事务回滚。

如果我们希望发生 IOException 时也能触发事务回滚,那么可以按照如下方式配置:

Java 配置:

@Transactional(rollbackFor = IOException.class)\
public void handle2() {\
    jdbcTemplate.update("update user set money = ? where username=?;", 1, "zhangsan");\
    accountService.handle1();\
}

5.4 是否只读

只读事务一般设置在查询方法上,但不是所有的查询方法都需要只读事务,要看具体情况。

一般来说,如果这个业务方法只有一个查询 SQL,那么就没必要添加事务,强行添加最终效果适得其反。

但是如果一个业务方法中有多个查询 SQL,情况就不一样了:多个查询 SQL,默认情况下,每个查询 SQL 都会开启一个独立的事务,这样,如果有并发操作修改了数据,那么多个查询 SQL 就会查到不一样的数据。此时,如果我们开启事务,并设置为只读事务,那么多个查询 SQL 将被置于同一个事务中,多条相同的 SQL 在该事务中执行将会获取到相同的查询结果。

Spring事务——传播性的更多相关文章

  1. spring 事务传播性

    一.什么是事务传播性 大白话讲就是,方法之间互相调用的时候,事务如何传播,比如A()调用B(),B()的事务是和A()共用一个事务(失败一起提交)? 还是新事务(两者事务互不影响)?,还是说B()不需 ...

  2. Spring事务传播性

    事务是逻辑处理原子性的保证手段,通过使用事务控制,可以极大的避免出现逻辑处理失败导致的脏数据等问题.事务最重要的两个特性,是事务的传播级别和数据隔离级别.传播级别定义的是事务的控制范围,事务隔离级别定 ...

  3. spring事务传播性与隔离级别

    事务的7种传播级别: 1)PROPAGATION_REQUIRED:支持当前事务,没有事务就新建一个. 2)PROPAGATION_SUPPORTS:支持当前事务,如果没有事务,以非事务方式处理 3) ...

  4. 事务传播性、隔离性与MVCC

    一.事务传播性 1.1 什么是事务的传播性 事务的传播性一般在事务嵌套时候使用,比如在事务A里面调用了另外一个使用事务的方法,那么这俩个事务是各自作为独立的事务执行提交,还是内层的事务合并到外层的事务 ...

  5. 理解 spring 事务传播行为与数据隔离级别

    事务,是为了保障逻辑处理的原子性.一致性.隔离性.永久性. 通过事务控制,可以避免因为逻辑处理失败而导致产生脏数据等等一系列的问题. 事务有两个重要特性: 事务的传播行为 数据隔离级别 1.事务传播行 ...

  6. Spring的事务传播性与隔离级别以及实现事物回滚

    一.事务的四个特性(ACID) 原子性(Atomicity):一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做,要么全部做. 一致性(Consistency): 数据不会因为事务的执行而 ...

  7. Spring的事务传播性

    事务是逻辑处理原子性的保证手段,通过使用事务控制,可以极大的避免出现逻辑处理失败导致的脏数据等问题.事务最重要的两个特性,是事务的传播级别和数据隔离级别.传播级别定义的是事务的控制范围,事务隔离级别定 ...

  8. 关于spring 事物传播性的研究

    spring的一大特色就是数据库事务管理方便,我们在代码中编写代码时,看不到事务的使用,关键是spring 使用了AOP进行事务拦截.   这篇文章主要介绍spring的事务传播性.   1.为什么要 ...

  9. spring事务传播机制实例讲解

    http://kingj.iteye.com/blog/1680350   spring事务传播机制实例讲解 博客分类:   spring java历险     天温习spring的事务处理机制,总结 ...

  10. 事务、事务特性、事务隔离级别、spring事务传播特性

    事务.事务特性.事务隔离级别.spring事务传播特性   1.什么是事务: 事务是程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原子性(要么成功, ...

随机推荐

  1. 【python_PAT_乙类】1007_素数对猜想 ,Python运行超时解决方案

    题目: 让我们定义d​n​​为:d​n​​=p​n+1​​−p​n​​,其中p​i​​是第i个素数.显然有d​1​​=1,且对于n>1有d​n​​是偶数."素数对猜想"认为& ...

  2. 树莓派启动后自动发送本地IP 到指定邮箱

    在 /etc/init.d   目录下建立 GetLocalip.py 文件 #coding: utf-8 import smtplib from email.mime.text import MIM ...

  3. 后台调用 WEBAPI 几种方式

    示例是调用谷歌短网址的API. 1. HttpClient方式: public static async void DoAsyncPost() { DateTime dateBegin = DateT ...

  4. 设置mode='out-on'导致路由切换过快路由加载报错 Failed to execute 'insertBefore' on 'Node'

    原代码: 解决代码: 原因未知

  5. reflection反射

    reflection反射 动态和静态语言 动态语言 动态语言就是一类在运行时可以改变其结构的语言,通俗点说就是在运行时代码可以根据某些条件改变自身结构 主要动态语言:object-C,C#,JavaS ...

  6. python 循环 类型转换

  7. 在LaTeX中使用BibTeX时的一个问题及其解决:编译PDF不随bib文件更新

    问题:更新bib文件之后,编译tex文件输出的PDF文件没有相应的更新. 原理: bbl文件才是引文的信息,bib文件只是用于生成bbl文件的一个"数据集"而已. 一般来说,LaT ...

  8. 对css及css3的大致整理(查漏补缺)

  9. linux shell 目录

    linux shell 目录 目录 linux shell 目录 类型 unix支持三大主流shell linux支持的shell(可有四种) 部分相关命令 查询进程 ps pstree kill 查 ...

  10. Windows安装使用Chocolatey 包软件管理(类似 rpm , yum, brew , apt-get 包管理器工具)

    Windows也能像Linux或者Mac那样命令行安装管理软件了,,,真的太方便了 下载安装 使用window powershell 用管理员运行 Set-ExecutionPolicy Bypass ...