@Transactional注解只能應用到public可見度的方法上,可以被應用於接口定義和接口方法,方法會覆蓋類上面聲明的事務。
常見坑點1:遇到檢查異常時,事務開啟,也無法回滾。 例如下面這段代碼,用戶依舊增加成功,並沒有因為后面遇到檢查異常而回滾!!
@Transactional public int insertUser(User user) throws Exception{ // 新增用戶信息 int rows = userMapper.insertUser(user); // 新增用戶崗位關聯 insertUserPost(user); // 新增用戶與角色管理 insertUserRole(user); // 模擬拋出SQLException異常 boolean flag = true; if (flag){ throw new SQLException("發生異常了.."); } return rows; }
原因分析:因為Spring的默認的事務規則是遇到運行異常(RuntimeException)和程序錯誤(Error)才會回滾。如果想針對非檢查異常進行事務回滾,可以在@Transactional 注解里使用 rollbackFor 屬性明確指定異常。
例如下面這樣,就可以正常回滾:
@Transactional(rollbackFor = Exception.class) public int insertUser(User user) throws Exception{ // 新增用戶信息 int rows = userMapper.insertUser(user); // 新增用戶崗位關聯 insertUserPost(user); // 新增用戶與角色管理 insertUserRole(user); // 模擬拋出SQLException異常 boolean flag = true; if (flag){ throw new SQLException("發生異常了.."); } return rows; }
常見坑點2: 在業務層捕捉異常后,發現事務不生效。 這是許多新手都會犯的一個錯誤,在業務層手工捕捉並處理了異常,你都把異常“吃”掉了,Spring自然不知道這里有錯,更不會主動去回滾數據。
例如:下面這段代碼直接導致用戶新增的事務回滾沒有生效。
@Transactional public int insertUser(User user) throws Exception{ // 新增用戶信息 int rows = userMapper.insertUser(user); // 新增用戶崗位關聯 insertUserPost(user); // 新增用戶與角色管理 insertUserRole(user); // 模擬拋出SQLException異常 boolean flag = true; if (flag) { try{ // 謹慎:盡量不要在業務層捕捉異常並處理 throw new SQLException("發生異常了.."); } catch (Exception e){ e.printStackTrace(); } } return rows; }
推薦做法:在業務層統一拋出異常,然后在控制層統一處理。
@Transactional public int insertUser(User user) throws Exception { // 新增用戶信息 int rows = userMapper.insertUser(user); // 新增用戶崗位關聯 insertUserPost(user); // 新增用戶與角色管理 insertUserRole(user); // 模擬拋出SQLException異常 boolean flag = true; if (flag) { throw new RuntimeException("發生異常了.."); } return rows; }
Transactional注解的常用屬性表:
屬性 | 說明 |
---|---|
propagation | 事務的傳播行為,默認值為 REQUIRED。 |
isolation | 事務的隔離度,默認值采用 DEFAULT |
timeout | 事務的超時時間,默認值為-1,不超時。如果設置了超時時間(單位秒),那么如果超過該時間限制了但事務還沒有完成,則自動回滾事務。 |
read-only | 指定事務是否為只讀事務,默認值為 false;為了忽略那些不需要事務的方法,比如讀取數據,可以設置 read-only 為 true。 |
rollbackFor | 用於指定能夠觸發事務回滾的異常類型,如果有多個異常類型需要指定,各類型之間可以通過逗號分隔。{xxx1.class, xxx2.class,……} |
noRollbackFor | 拋出 no-rollback-for 指定的異常類型,不回滾事務。{xxx1.class, xxx2.class,……} |