Spring 事務管理

📢 本文由 gemini-2.5-flash 翻譯

事務

事務是一組操作的集合,它是一個不可分割的工作單位,這些操作要嘛同時成功,要嘛同時失敗。

操作:

  • 開啟事務 (一組操作開始前,開啟事務):start transaction / begin
  • 提交事務 (這組操作全部成功後,提交事務):commit
  • 回滾事務 (中間任何一個操作出現例外,回滾事務):rollback

假設刪除部門後要繼續刪除該部門員工。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@Service
public class DeptServiceImpl implements DeptService{
    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private EmpMapper empMapper;
    
    @Override
    public void delete(Integer id{
        //1.刪除部門
        deptMapper.delete(id);
        
        // 假如這裡出現錯誤,只刪除了部門,沒刪除員工
        
        //2.根據部門id,刪除部門下的員工資訊
        empMapper.deleteByDetId(id);
    }
}         

如上所示,將會留下不存在部門的員工,造成了資料的不一致。

Spring 事務管理

註解:@Transactional,位置:Service 層方法、類別、介面上

作用:將當前方法交給 Spring 進行事務管理,方法執行前開啟事務;成功執行完畢提交事務;出現例外回滾事務。

上述方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Service
public class DeptServiceImpl implements DeptService{
    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private EmpMapper empMapper;
    
    @Transactional // 交給Spring進行事務管理
    @Override
    public void delete(Integer id{
        //1.刪除部門
        deptMapper.delete(id);
        
        //2.根據部門id,刪除部門下的員工資訊
        empMapper.deleteByDetId(id);
    }
}

同時可以開啟事務管理日誌。

1
2
3
4
#Spring事務管理日誌
logging:
  level:
    org.springframework.jdbc.support.JdbcTransactionManager: debug

事務屬性 - 回滾

預設情況下,只有出現執行期例外 (RuntimeException) 才回滾事務,透過 rollbackFor 屬性可以控制出現何種例外類型時,回滾事務。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@Service
public class DeptServiceImpl implements DeptService{
    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private EmpMapper empMapper;
    
    // 所有例外都回滾
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Integer id{
        //1.刪除部門
        deptMapper.delete(id);
        
        //2.根據部門id,刪除部門下的員工資訊
        empMapper.deleteByDetId(id);
    }
}         

事務屬性 - 傳播行為

事務傳播行為是指當一個事務方法被另一個事務方法呼叫時,這個事務方法應該如何進行事務。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Transactional
public void a(){
    // code
    userServices.b();
    // code
}

@Transactional
public void b(){
    // code
}

上述 a 呼叫了 b,b 該如何進行事務,加入 a 的事務或者單獨開一個事務。

可以透過屬性 propagation 進行控制。

屬性值描述
REQUIRED (預設值)需要事務,有則加入,無則建立新事務
REQUIRES_NEW需要事務,無論有無都建立新事務
SUPPORTS支援事務,有則加入,無則在無事務狀態執行
NOT_SUPPORTS不支援事務,有事務則暫停,在無事務下執行
MANDATORY必須有事務,否則拋出例外
NEVER必須無事務,否則拋出例外

使用範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Transactional
public void a(){
    // code
    userServices.b();
    // code
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void b(){
    // code
}