@Transactional 的使用
這個事務注解可以用在類上,也可以用在方法上:
- 事務注解標記到服務組件類級別,相當於為該服務組件的每個服務方法都應用了這個注解
- 事務注解應用在方法級別,是更細粒度的一種事務注解方式
- 如果某個方法和該方法所屬類上都有事務注解屬性,優先使用方法上的事務注解屬性
另外,Spring 支持三個不同的事務注解:
- Spring 事務注解 org.springframework.transaction.annotation.Transactional(官方推薦)
- JTA 事務注解 javax.transaction.Transactional
- EJB 3 事務注解 javax.ejb.TransactionAttribute
@Transactional 注解參數
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { /** * value 和 transactionManager 屬性是一樣的意思。當配置了多個事務管理器時,可以使用該屬性指定選擇哪個事務管理器 */ @AliasFor("transactionManager") String value() default ""; @AliasFor("value") String transactionManager() default ""; /** * 事務的傳播行為 */ Propagation propagation() default Propagation.REQUIRED; /** * 事務的隔離級別 */ Isolation isolation() default Isolation.DEFAULT; /** * 事務的超時時間,默認為 -1 */ int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; /** * 是否只讀,默認 false */ boolean readOnly() default false; /** * 需要回滾的異常,可以指定多個異常類型,不指定默認只回滾 RuntimeException 和 Error */ Class<? extends Throwable>[] rollbackFor() default {}; String[] rollbackForClassName() default {}; /** * 不需要回滾的異常 */ Class<? extends Throwable>[] noRollbackFor() default {}; String[] noRollbackForClassName() default {}; }
Spring 會將事務提交切換到手動模式
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean { @Override protected void doBegin(Object transaction, TransactionDefinition definition) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; Connection con = null; try { if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) { Connection newCon = obtainDataSource().getConnection(); if (logger.isDebugEnabled()) { logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction"); } txObject.setConnectionHolder(new ConnectionHolder(newCon), true); } txObject.getConnectionHolder().setSynchronizedWithTransaction(true); con = txObject.getConnectionHolder().getConnection(); Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition); txObject.setPreviousIsolationLevel(previousIsolationLevel); txObject.setReadOnly(definition.isReadOnly()); if (con.getAutoCommit()) { txObject.setMustRestoreAutoCommit(true); if (logger.isDebugEnabled()) { logger.debug("Switching JDBC Connection [" + con + "] to manual commit"); } con.setAutoCommit(false); // 取消自動提交 } prepareTransactionalConnection(con, definition); txObject.getConnectionHolder().setTransactionActive(true); int timeout = determineTimeout(definition); if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { txObject.getConnectionHolder().setTimeoutInSeconds(timeout); } if (txObject.isNewConnectionHolder()) { TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder()); } } catch (Throwable ex) { if (txObject.isNewConnectionHolder()) { DataSourceUtils.releaseConnection(con, obtainDataSource()); txObject.setConnectionHolder(null, false); } throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex); } }
事務配置 TransactionDefinition
事務管理器接口 PlatformTransactionManager 通過 getTransaction(TransactionDefinition definition) 方法得到事務,這個方法里面的參數是 TransactionDefinition,這個類就定義了一些基本的事務屬性。
事務屬性可以理解成事務的一些基本配置,描述了事務策略如何應用到方法上。事務屬性包含了 5 個方面:
常用實現類為:DefaultTransactionDefinition,TransactionAttribute 接口也繼承自此接口
public interface TransactionDefinition { // 7 種類型的事務傳播行為,如果當前沒有事務,則執行與 PROPAGATION_REQUIRED 類似的操作 int PROPAGATION_REQUIRED = 0; // 如果當前沒有事務,就新建一個事務,如果已經在一個事務中,加入到這個事務中。這是最常見的選擇 int PROPAGATION_SUPPORTS = 1; // 支持當前事務,如果當前沒有事務,就以非事務的方式執行 int PROPAGATION_MANDATORY = 2; // 使用當前的事務,如果當前沒有事務,就拋出異常 int PROPAGATION_REQUIRES_NEW = 3; // 新建事務,如果當前存在事務,把當前事務掛起 int PROPAGATION_NOT_SUPPORTED = 4; // 以非事務的方式執行,如果當前存在事務,就把當前事務掛起 int PROPAGATION_NEVER = 5; // 以非事務的方式執行,如果當前存在事務,則拋出異常 int PROPAGATION_NESTED = 6; // 如果當前存在事務,則在嵌套事務(它是一個子事務,但它仍還是外部事務的一部分,外部事務提交了它才提交)內執行 // 4 種:隔離級別 // PlatformTransactionManager 的默認隔離級別(對大多數數據庫來說就是 ISOLATION_ READ_COMMITTED // MySQL 默認采用 ISOLATION_REPEATABLE_READ,Oracle 默認采用 READ__COMMITTED int ISOLATION_DEFAULT = -1; // 讀未提交,最低的隔離級別。可能導致臟、幻讀、不可重復讀 int ISOLATION_READ_UNCOMMITTED = 1; // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED; // 讀已提交,大多數數據庫的默認級別。可防止臟讀,但幻讀、不可重復讀仍可能發生 int ISOLATION_READ_COMMITTED = 2; // same as java.sql.Connection.TRANSACTION_READ_COMMITTED; // 可重復讀。該隔離級別確保如果在事務中查詢了某個數據集,你至少還能再次查詢到相同的數據集,即使其它事務修改了所查詢的數據 // 可防止臟讀,不可重復讀,但幻讀仍可能發生 int ISOLATION_REPEATABLE_READ = 4; // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ; // 序列化。代價最大、可靠性最高的隔離級別,所有的事務都是按順序一個接一個地執行。避免所有不安全讀取 int ISOLATION_SERIALIZABLE = 8; // same as java.sql.Connection.TRANSACTION_SERIALIZABLE; // 默認的超時時間,-1 表示不超時(單位是秒) // 如果超過該時間限制,但事務還沒有完成,則自動回滾事務 int TIMEOUT_DEFAULT = -1; /** * 返回事務的傳播行為(一共7種) */ default int getPropagationBehavior() { return PROPAGATION_REQUIRED; } /** * 返回事務的隔離級別。事務管理器根據它來控制另外一個事務可以看到本事務內的哪些數據 */ default int getIsolationLevel() { return ISOLATION_DEFAULT; } /** * 返回超時時間(事務必須在多少秒內完成) */ default int getTimeout() { return TIMEOUT_DEFAULT; } /** * 事務是否只讀(事務管理器能夠根據這個返回值進行優化,確保事務是只讀的) */ default boolean isReadOnly() { return false; } /** * 事務的名字,可以為 null */ @Nullable default String getName() { return null; } /** * 靜態構建方法 * 返回帶有默認值且不可修改的 TransactionDefinition */ static TransactionDefinition withDefaults() { return StaticTransactionDefinition.INSTANCE; } }
事務四大特性:ACID
- Atomicity(原子性):事務是一個原子操作,由一系列動作組成。事務的原子性確保動作要么全部完成,要么完全不起作用
- Consistency(一致性):一旦事務完成(不管成功還是失敗),系統必須確保它所建模的業務處於一致的狀態,而不會是部分完成部分失敗。在現實中的數據不應該被破壞
- Isolation(隔離性):可能有許多事務會同時處理相同的數據,因此每個事務都應該與其他事務隔離開來,防止數據損壞
- Durability(持久性):一旦事務完成,無論發生什么系統錯誤,它的結果都不應該受到影響,這樣就能從任何系統崩潰中恢復過來。通常情況下,事務的結果被寫到持久化存儲器中
CAP:Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區容錯性)
BASE 理論:Basically Available(基本可用)、Soft state(軟狀態)和 Eventually consistent(最終一致性)三個短語的縮寫
事務不生效的原因
確保業務和事務入口在同一個線程里,否則事務是不生效的
@Transactional 開啟的事務 ,或者是基於接口的,或者是基於類的,代理被創建。所以在同一個類中一個無事務的方法調用另一個有事務的方法,事務是不會起作用的
https://blog.csdn.net/f641385712/article/details/89602418
https://blog.csdn.net/f641385712/article/details/80445933
https://blog.csdn.net/f641385712/article/details/80445912