文章目錄
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,即非只讀事務
注意 在只讀事務中修改數據庫是會報錯的!
