더이상 쪼개어 질 수 없는 업무처리단위
작업의 단위
다 성공할 것이 아니면 모두 다 실패같은 쿼리는 조회할 때마다 동일트랜잭션이 진행중일 때는 해당 데이터에 대한 접근은 대기 상태장애가 발생하여도 트랜잭션의 결과는 유지//생성자에서 DataSource 객체 생성
private readonly dataSource: DataSource,
// 트랜잭션 사용방법
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
try{
await queryRunner.startTransaction(); // Transaction start
queryRunner.manaer.메서드를 이용하여 DB 로직 처리
await queryRunner.commitTransaction(); // 성공시, Commit
}catch{
await queryRunner.rollbackTransaction(); // 오류시, RollBack
}finally{
await queryRunner.release(); // Transaction close
}
DataSource의 메서드
- createQueryBuilder : 복잡한 쿼리가 필요할 때 select() from() where() 등의 메서드를 사용하여 복잡한 쿼리를 사용할 수 있다.
- createQueryRunner : 단순한 datasource 메서드를 사용할 때 사용
격리 수준이 높아질 수록 안전성(격리성)이 높아지나, 속도(동시성)가 느려진다.
1레벨(Read-Uncommitted) : Dirty-Read , Non-Repeatable-Read, Phantom-Read
2레벨(Read-committed) : Non-Repeatable-Read, Phantom-Read
3레벨(Repeatable-Read) : Phantom-Read
4레벨(Serializable) : X
Dirty : commit이 되지 않은 것들이 조회되는 것 (일관성 무시)
Repeatable : 반복적으로 조회되는 시, 비일관적인 데이터가 조회되는 것 ex)외부에서 데이터 조작 (격리성 무시)
Phantom : 존재하지 않는 데이터가 조회되는 것
Serializable : 데이터에 대한 Rock을 걸어 트랜잭션이 종료될 때까지 데이터에 대한 접근을 하지 못하게 한다.(성능이 상대적으로 좋지 않다.)
격리 수준이 높아질 수록 속도가 느려진다.
mysql은 기본 3레벨이 설정되어 있으면 3레벨에서 phantom-Read 까지 차단한다.
await queryRunner.startTransaction('READ UNCOMMITTED');
await queryRunner.startTransaction('SERIALIZABLE');
// 조회시 락을 걸고 조회함으로써, 다른 쿼리에서 조회 못하게 막음(대기시킴) => Select ~ For Update
const payment = await queryRunner.manager.find(Payment, {
lock: { mode: 'pessimistic_write' },
});
정리 : isolation-level 및 락 설정을 상황에 맞게 적용하여야 한다.