📢 この記事は 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
}
|