• 聊一聊对“事务”的理解


    什么是事务

    事务即英文Transaction,在软件开发过程中,难免需要考虑处理事务。从微观层面看亦或者从成员最早了解到这个词汇看,事务通常指多条写入数据库的语句需要并发成功执行,从宏观层面看得话则是客户端发出的并发请求需要一致性并发成功完成,即要么都成功要么都失败。这样以来常见的事务分为了单库事务、分布式事务,当然事务数也演进为了一个衡量服务性能的度量单位,比如在推进性能测试验证时用到的tps指标。

    事务的特点

    根据事务的定义,可总结出四个特点ACID,即:

    原子性(Atomicity): 事务是数据库的逻辑工作单位,事务中包括的诸操作要么全成功,要么全失败。

    一致性(Consistency): 事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。当然这个看上去更多是从微观层面提炼的特点描述。

    隔离性(Isolation): 一个事务的执行不能被其他事务干扰。

    持续性/永久性(Durability): 一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。

    事务的控制

    事务的控制无非就是对事务的特点进行严格控制以对活动操作的完整准备性提供保障。微观层面的事务控制也是我们最常见的事务控制,无非还是基于数据库层面得。作为Java语言出身的编码人士,此刻第一想到的便是Spring框架中的@Transactional注解,在大多数人看来使用了@Transactional注解即可控制事务以达成特点的要求。然而真的是那样吗,我们还是看看这个注解的描述。

    1. @Target({ElementType.TYPE, ElementType.METHOD})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Inherited
    4. @Documented
    5. public @interface Transactional {
    6. /**
    7. * Alias for {@link #transactionManager}.
    8. * @see #transactionManager
    9. */
    10. @AliasFor("transactionManager")
    11. String value() default "";
    12. /**
    13. * A <em>qualifier</em> value for the specified transaction.
    14. * <p>May be used to determine the target transaction manager, matching the
    15. * qualifier value (or the bean name) of a specific
    16. * {@link org.springframework.transaction.TransactionManager TransactionManager}
    17. * bean definition.
    18. * @since 4.2
    19. * @see #value
    20. * @see org.springframework.transaction.PlatformTransactionManager
    21. * @see org.springframework.transaction.ReactiveTransactionManager
    22. */
    23. @AliasFor("value")
    24. String transactionManager() default "";
    25. /**
    26. * Defines zero (0) or more transaction labels.
    27. * <p>Labels may be used to describe a transaction, and they can be evaluated
    28. * by individual transaction managers. Labels may serve a solely descriptive
    29. * purpose or map to pre-defined transaction manager-specific options.
    30. * <p>See the documentation of the actual transaction manager implementation
    31. * for details on how it evaluates transaction labels.
    32. * @since 5.3
    33. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#getLabels()
    34. */
    35. String[] label() default {};
    36. /**
    37. * The transaction propagation type.
    38. * <p>Defaults to {@link Propagation#REQUIRED}.
    39. * @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()
    40. */
    41. Propagation propagation() default Propagation.REQUIRED;
    42. /**
    43. * The transaction isolation level.
    44. * <p>Defaults to {@link Isolation#DEFAULT}.
    45. * <p>Exclusively designed for use with {@link Propagation#REQUIRED} or
    46. * {@link Propagation#REQUIRES_NEW} since it only applies to newly started
    47. * transactions. Consider switching the "validateExistingTransactions" flag to
    48. * "true" on your transaction manager if you'd like isolation level declarations
    49. * to get rejected when participating in an existing transaction with a different
    50. * isolation level.
    51. * @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()
    52. * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction
    53. */
    54. Isolation isolation() default Isolation.DEFAULT;
    55. /**
    56. * The timeout for this transaction (in seconds).
    57. * <p>Defaults to the default timeout of the underlying transaction system.
    58. * <p>Exclusively designed for use with {@link Propagation#REQUIRED} or
    59. * {@link Propagation#REQUIRES_NEW} since it only applies to newly started
    60. * transactions.
    61. * @return the timeout in seconds
    62. * @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
    63. */
    64. int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
    65. /**
    66. * The timeout for this transaction (in seconds).
    67. * <p>Defaults to the default timeout of the underlying transaction system.
    68. * <p>Exclusively designed for use with {@link Propagation#REQUIRED} or
    69. * {@link Propagation#REQUIRES_NEW} since it only applies to newly started
    70. * transactions.
    71. * @return the timeout in seconds as a String value, e.g. a placeholder
    72. * @since 5.3
    73. * @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
    74. */
    75. String timeoutString() default "";
    76. /**
    77. * A boolean flag that can be set to {@code true} if the transaction is
    78. * effectively read-only, allowing for corresponding optimizations at runtime.
    79. * <p>Defaults to {@code false}.
    80. * <p>This just serves as a hint for the actual transaction subsystem;
    81. * it will <i>not necessarily</i> cause failure of write access attempts.
    82. * A transaction manager which cannot interpret the read-only hint will
    83. * <i>not</i> throw an exception when asked for a read-only transaction
    84. * but rather silently ignore the hint.
    85. * @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()
    86. * @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
    87. */
    88. boolean readOnly() default false;
    89. /**
    90. * Defines zero (0) or more exception {@linkplain Class classes}, which must be
    91. * subclasses of {@link Throwable}, indicating which exception types must cause
    92. * a transaction rollback.
    93. * <p>By default, a transaction will be rolled back on {@link RuntimeException}
    94. * and {@link Error} but not on checked exceptions (business exceptions). See
    95. * {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)}
    96. * for a detailed explanation.
    97. * <p>This is the preferred way to construct a rollback rule (in contrast to
    98. * {@link #rollbackForClassName}), matching the exception type, its subclasses,
    99. * and its nested classes. See the {@linkplain Transactional class-level javadocs}
    100. * for further details on rollback rule semantics and warnings regarding possible
    101. * unintentional matches.
    102. * @see #rollbackForClassName
    103. * @see org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class)
    104. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
    105. */
    106. Class<? extends Throwable>[] rollbackFor() default {};
    107. /**
    108. * Defines zero (0) or more exception name patterns (for exceptions which must be a
    109. * subclass of {@link Throwable}), indicating which exception types must cause
    110. * a transaction rollback.
    111. * <p>See the {@linkplain Transactional class-level javadocs} for further details
    112. * on rollback rule semantics, patterns, and warnings regarding possible
    113. * unintentional matches.
    114. * @see #rollbackFor
    115. * @see org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String)
    116. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
    117. */
    118. String[] rollbackForClassName() default {};
    119. /**
    120. * Defines zero (0) or more exception {@link Class Classes}, which must be
    121. * subclasses of {@link Throwable}, indicating which exception types must
    122. * <b>not</b> cause a transaction rollback.
    123. * <p>This is the preferred way to construct a rollback rule (in contrast to
    124. * {@link #noRollbackForClassName}), matching the exception type, its subclasses,
    125. * and its nested classes. See the {@linkplain Transactional class-level javadocs}
    126. * for further details on rollback rule semantics and warnings regarding possible
    127. * unintentional matches.
    128. * @see #noRollbackForClassName
    129. * @see org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class)
    130. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
    131. */
    132. Class<? extends Throwable>[] noRollbackFor() default {};
    133. /**
    134. * Defines zero (0) or more exception name patterns (for exceptions which must be a
    135. * subclass of {@link Throwable}) indicating which exception types must <b>not</b>
    136. * cause a transaction rollback.
    137. * <p>See the {@linkplain Transactional class-level javadocs} for further details
    138. * on rollback rule semantics, patterns, and warnings regarding possible
    139. * unintentional matches.
    140. * @see #noRollbackFor
    141. * @see org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String)
    142. * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
    143. */
    144. String[] noRollbackForClassName() default {};
    145. }

    从定义来看这个注解的属性主要体现在从这么几个方面控制:

    1. 作用范围,不仅仅可以添加在方法上面,还可以添加到类级别上。

    当注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。如果类级别配置了 @transactional,方法级别也配置了 @transactional,应用程序会以方法级别的事务属性信息来管理事务。

    2.作用场景,即在什么情况下提交事务或者回滚事务,将有@Transactional相关的配置参数来决定。

    参数名释义举例
    value事务管理器设置 Spring 容器中的 Bean 名称,这个 Bean 需要实现接口 PlatformTransactionManager。
    isolation事务隔离级别
    1. /**
    2. * Use the default isolation level of the underlying datastore.
    3. * All other levels correspond to the JDBC isolation levels.
    4. * @see java.sql.Connection
    5. */
    6. DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
    7. /**
    8. * A constant indicating that dirty reads, non-repeatable reads and phantom reads
    9. * can occur. This level allows a row changed by one transaction to be read by
    10. * another transaction before any changes in that row have been committed
    11. * (a "dirty read"). If any of the changes are rolled back, the second
    12. * transaction will have retrieved an invalid row.
    13. * @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
    14. */
    15. READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
    16. /**
    17. * A constant indicating that dirty reads are prevented; non-repeatable reads
    18. * and phantom reads can occur. This level only prohibits a transaction
    19. * from reading a row with uncommitted changes in it.
    20. * @see java.sql.Connection#TRANSACTION_READ_COMMITTED
    21. */
    22. READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
    23. /**
    24. * A constant indicating that dirty reads and non-repeatable reads are
    25. * prevented; phantom reads can occur. This level prohibits a transaction
    26. * from reading a row with uncommitted changes in it, and it also prohibits
    27. * the situation where one transaction reads a row, a second transaction
    28. * alters the row, and the first transaction rereads the row, getting
    29. * different values the second time (a "non-repeatable read").
    30. * @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
    31. */
    32. REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
    33. /**
    34. * A constant indicating that dirty reads, non-repeatable reads and phantom
    35. * reads are prevented. This level includes the prohibitions in
    36. * {@code ISOLATION_REPEATABLE_READ} and further prohibits the situation
    37. * where one transaction reads all rows that satisfy a {@code WHERE}
    38. * condition, a second transaction inserts a row that satisfies that
    39. * {@code WHERE} condition, and the first transaction rereads for the
    40. * same condition, retrieving the additional "phantom" row in the second read.
    41. * @see java.sql.Connection#TRANSACTION_SERIALIZABLE
    42. */
    43. SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);

     

    propagation事务传播行为
    1. /**
    2. * Support a current transaction, create a new one if none exists.
    3. * Analogous to EJB transaction attribute of the same name.
    4. * <p>This is the default setting of a transaction annotation.
    5. */
    6. REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
    7. /**
    8. * Support a current transaction, execute non-transactionally if none exists.
    9. * Analogous to EJB transaction attribute of the same name.
    10. * <p>Note: For transaction managers with transaction synchronization,
    11. * {@code SUPPORTS} is slightly different from no transaction at all,
    12. * as it defines a transaction scope that synchronization will apply for.
    13. * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
    14. * will be shared for the entire specified scope. Note that this depends on
    15. * the actual synchronization configuration of the transaction manager.
    16. * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
    17. */
    18. SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
    19. /**
    20. * Support a current transaction, throw an exception if none exists.
    21. * Analogous to EJB transaction attribute of the same name.
    22. */
    23. MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
    24. /**
    25. * Create a new transaction, and suspend the current transaction if one exists.
    26. * Analogous to the EJB transaction attribute of the same name.
    27. * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
    28. * on all transaction managers. This in particular applies to
    29. * {@link org.springframework.transaction.jta.JtaTransactionManager},
    30. * which requires the {@code javax.transaction.TransactionManager} to be
    31. * made available to it (which is server-specific in standard Java EE).
    32. * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
    33. */
    34. REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
    35. /**
    36. * Execute non-transactionally, suspend the current transaction if one exists.
    37. * Analogous to EJB transaction attribute of the same name.
    38. * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
    39. * on all transaction managers. This in particular applies to
    40. * {@link org.springframework.transaction.jta.JtaTransactionManager},
    41. * which requires the {@code javax.transaction.TransactionManager} to be
    42. * made available to it (which is server-specific in standard Java EE).
    43. * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
    44. */
    45. NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
    46. /**
    47. * Execute non-transactionally, throw an exception if a transaction exists.
    48. * Analogous to EJB transaction attribute of the same name.
    49. */
    50. NEVER(TransactionDefinition.PROPAGATION_NEVER),
    51. /**
    52. * Execute within a nested transaction if a current transaction exists,
    53. * behave like {@code REQUIRED} otherwise. There is no analogous feature in EJB.
    54. * <p>Note: Actual creation of a nested transaction will only work on specific
    55. * transaction managers. Out of the box, this only applies to the JDBC
    56. * DataSourceTransactionManager. Some JTA providers might support nested
    57. * transactions as well.
    58. * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
    59. */
    60. NESTED(TransactionDefinition.PROPAGATION_NESTED);

    timeout事务超时时间单位为秒,默认值为-1,当事务超时时会抛出异常,进行回滚操作。
    readOnly是否开启只读事务是否开启只读事务,默认 false
    rollbackFor回滚事务异常类定义当方法中出异常,且异常类和该参数指定的类相同时,进行回滚操作,否则提交事务。
    noRollbackFor非回滚事务异常类定义

    指定发生哪些异常不回滚事务,当方法中出异常,且异常类和该参数指定的类相同时,不回滚而是将继续提交事务。

    当然@Transactional并非直接加到方法头或者类头上就万事大吉了,还需要了解这么几个潜规则:

    1.由于自调用方法不走Spring的代理类,所以无法确保private方法无法受到Spring  AOP的代理,默认为私有private方法设置@Transactional注解无法生效事务。除非使用AspectJ做静态织入,否则需要确保只有public方法才设置@Transactional注解
    2.只有异常传播出了标记了@Transactional注解的方法,事务才能遇到异常的情况下回滚,同时需要避免 catch住异常,或者通过TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()手动回滚事务。默认情况下,出现 RuntimeException(非受检异常)或Error的时候,Spring 才会回滚事务,因此我们需要人为的去设置@Transactional(rollbackFor = Exception.class),来突破默认不回滚受检异常的限制
    3.默认事务传播策略是REQUIRED,即子方法会复用当前事务,当子方法出异常后会回滚当前事务,导致父方法也无法提交事务。如果不需要这样的效果,则需要人为的修改设置传播方式即propagation参数为REQUIRES_NEW方式的事务传播策略,让子方法运行在独立事务中。

    当然还有分布式事务的控制,则显得稍有复杂,待笔者抽时间整理好后再呈现。

  • 相关阅读:
    多位数按键操作(不闪烁)
    PYTHON快捷键合集!学会让你成为大一最靓的仔
    R语言ggplot2可视化:使用ggpubr包的ggpaired函数可视化配对数据(可视化箱图并使用线段连接配对的数据点)
    为什么说“分布式架构”才是AR眼镜的未来
    基于网络的虚拟仪器测试系统
    maven 生命周期 `* `
    SpringSecurity(JWT、SecurityConfig、Redis)
    3Dmax建模教程详细步骤3D建模速成入门到高级教程
    为什么从没有负值的数据中绘制的小提琴图(Violin Plot)会出现负值部分?
    别再低效筛选数据了!试试pandas query函数
  • 原文地址:https://blog.csdn.net/sinat_34206747/article/details/125567634