Java開發學習(二十二)——Spring事務屬性、事務傳播行為
一、事務配置
上面這些屬性都可以在
@Transactional
註解的引數上進行設定。
readOnly:true只讀事務,false讀寫事務,增刪改要設為false,查詢設為true。
timeout:設定超時時間單位秒,在多長時間之內事務沒有提交成功就自動回滾,-1表示不設定超時時間。
rollbackFor:當出現指定異常進行事務回滾
noRollbackFor:當出現指定異常不進行事務回滾
思考:出現異常事務會自動回滾,這個是我們之前就已經知道的
noRollbackFor是設定對於指定的異常不回滾,這個好理解
rollbackFor是指定回滾異常,對於異常事務不應該都回滾麼,為什麼還要指定?
這塊需要更正一個地方,並不是所有的異常都會回滾事務,比如下面的程式碼就不會回滾
public interface AccountService { /** * 轉賬操作 * @param out 傳出方 * @param in 轉入方 * @param money 金額 */ //配置當前介面方法具有事務 public void transfer(String out,String in ,Double money) throws IOException; } @Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Transactional public void transfer(String out,String in ,Double money) throws IOException{ accountDao。outMoney(out,money); //int i = 1/0; //這個異常事務會回滾 if(true){ throw new IOException(); //這個異常事務就不會回滾 } accountDao。inMoney(in,money); } }
出現這個問題的原因是,Spring的事務只會對
Error異常
和
RuntimeException異常
及其子類進行事務回顧,其他的異常型別是不會回滾的,對應IOException不符合上述條件所以不回滾
此時就可以使用rollbackFor屬性來設定出現IOException異常不回滾
@Service
public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Transactional(rollbackFor = {IOException。class}) public void transfer(String out,String in ,Double money) throws IOException{ accountDao。outMoney(out,money); //int i = 1/0; //這個異常事務會回滾 if(true){ throw new IOException(); //這個異常事務就不會回滾 } accountDao。inMoney(in,money); } }
rollbackForClassName等同於rollbackFor,只不過屬性為異常的類全名字串
noRollbackForClassName等同於noRollbackFor,只不過屬性為異常的類全名字串
isolation設定事務的隔離級別
DEFAULT :預設隔離級別, 會採用資料庫的隔離級別
READ_UNCOMMITTED : 讀未提交
READ_COMMITTED : 讀已提交
REPEATABLE_READ : 重複讀取
SERIALIZABLE: 序列化
介紹完上述屬性後,還有一個事務的傳播行為,先看下面的案例
二、轉賬業務追加日誌案例
2。1 需求分析
在上節部落格(
Java開發學習(二十一)——Spring事務簡介與事務角色解析
)環境的基礎上新增新的需求,完成轉賬後記錄日誌。
需求:實現任意兩個賬戶間轉賬操作,並對每次轉賬操作在資料庫進行留痕
需求微縮:A賬戶減錢,B賬戶加錢,資料庫記錄日誌
基於上述的業務需求,我們來分析下該如何實現:
①:基於轉賬操作案例新增日誌模組,實現資料庫中記錄日誌
②:業務層轉賬操作(transfer),呼叫減錢、加錢與記錄日誌功能
需要注意一點就是,我們這個案例的預期效果為:
無論轉賬操作是否成功,均進行轉賬操作的日誌留痕
2。2 環境準備
環境參考
Java開發學習(二十一)——Spring事務簡介與事務角色解析
,
在其基礎上,我們繼續往下寫
步驟1:建立日誌表
create table tbl_log( id int primary key auto_increment, info varchar(255), createDate datetime )
步驟2:新增LogDao介面
public interface LogDao { @Insert(“insert into tbl_log (info,createDate) values(#{info},now())”) void log(String info); }
步驟3:新增LogService介面與實現類
public interface LogService { void log(String out, String in, Double money); } @Service public class LogServiceImpl implements LogService { @Autowired private LogDao logDao; @Transactional public void log(String out,String in,Double money ) { logDao。log(“轉賬操作由”+out+“到”+in+“,金額:”+money); } }
步驟4:在轉賬的業務中新增記錄日誌
public interface AccountService { /** * 轉賬操作 * @param out 傳出方 * @param in 轉入方 * @param money 金額 */ //配置當前介面方法具有事務 public void transfer(String out,String in ,Double money)throws IOException ; } @Service public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Autowired private LogService logService; @Transactional public void transfer(String out,String in ,Double money) { try{ accountDao。outMoney(out,money); accountDao。inMoney(in,money); }finally { logService。log(out,in,money); } } }
步驟5:執行程式
當程式正常執行,tbl_account表中轉賬成功,tbl_log表中日誌記錄成功
當轉賬業務之間出現異常(int i =1/0),轉賬失敗,tbl_account成功回滾,但是tbl_log表未新增資料
這個結果和我們想要的不一樣,什麼原因?該如何解決?
失敗原因:日誌的記錄與轉賬操作隸屬同一個事務,同成功同失敗
最終效果:無論轉賬操作是否成功,日誌必須保留
三、事務傳播行為
對於上述案例的分析:
log方法、inMoney方法和outMoney方法都屬於增刪改,分別有事務T1,T2,T3
transfer因為加了@Transactional註解,也開啟了事務T
前面我們講過Spring事務會把T1,T2,T3都加入到事務T中
所以當轉賬失敗後,所有的事務都回滾,導致日誌沒有記錄下來
這和我們的需求不符,這個時候我們就想能不能讓log方法單獨是一個事務呢?
要想解決這個問題,就需要用到事務傳播行為,所謂的事務傳播行為指的是:
事務傳播行為:事務協調員對事務管理員所攜帶事務的處理態度。
具體如何解決,就需要用到之前我們沒有說的
propagation屬性
。
1。修改logService改變事務的傳播行為
@Service public class LogServiceImpl implements LogService { @Autowired private LogDao logDao; //propagation設定事務屬性:傳播行為設定為當前操作需要新事務 @Transactional(propagation = Propagation。REQUIRES_NEW) public void log(String out,String in,Double money ) { logDao。log(“轉賬操作由”+out+“到”+in+“,金額:”+money); } }
執行後,就能實現我們想要的結果,不管轉賬是否成功,都會記錄日誌。
2。事務傳播行為的可選值
作者:
|舊市拾荒|
原文連結:
https://www。cnblogs。com/xiaoyh/p/16412565。html