django의 transaction 사용법을 간단하게 설명하고, Mysql의 transaction 전략들을 알아본다.
간단하게 설명하자면 Django의 transaction은 아래와 같이 사용한다.
def _insert_audio_and_update_indexs(
self, project_id: int, index: int, text: str, speed: int, user_id: int
) -> dict:
"""
오디오를 지정한 위치에 생성하고, 뒤로 밀려나게 되는 audio의 index를 업데이트 합니다.
생성된 오디오 정보를 dict로 return
"""
with transaction.atomic():
self._update_audios_index(project_id, index, is_increase=True)
create_params = {
"project": project_id,
"index": index,
"text": text,
"speed": speed,
"user": user_id,
}
new_audio = audio_repo.create(create_params)
return new_audio
위의 함수는, 어떤 프로젝트에 1:N 관계에 있는 audio들의 index라는 컬럼 값을 1씩 증가 시키는 bulk update를 수행한 후, 새 audio를 만드는 로직을 갖고 있다. 기존의 audio들의 index 컬럼 값의 업데이트와 새로 만들어지는 audio는 비지니스 로직으로 하나의 연산으로 간주되므로, transaction 처리를 해주어야 한다. transaction.atomic context에서 에러가 감지되면, 변경사항은 DB에 적용되지 않고 rollback 될것이다.
당연하게도, Django의 transactoin은 Mysql의 transcation API를 호출하여 사용할 것이다.
Mysql의 transaction에 대하여 알아보자.
transaction
Transactions are atomic units of work that can be committed or rolled back. When a transaction makes multiple changes to the database, either all the changes succeed when the transaction is committed, or all the changes are undone when the transaction is rolled back.
Database transactions, as implemented byInnoDB
, have properties that are collectively known by the acronym ACID, for atomicity, consistency, isolation, and durability.
출처: Mysql 공식문서, https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_transaction
해석하자면,
transaction은 커밋되거나 롤백될 수 있는 하나의 작업 단위입니다. 트랜잭션이 데이터베이스를 여러 번 변경할 경우 트랜잭션이 커밋될 때 모든 변경사항이 성공하거나 트랜잭션이 롤백될 때 모든 변경사항이 실행 취소됩니다. InnoDB에 의해 구현된 데이터베이스 트랜잭션은 원자성, 일관성, 분리 및 내구성을 위해 ACID라는 약어로 총칭되는 속성을 갖습니다.
라는 뜻이다.
transaction을 만들 때 lock을 걸어서 데이터의 일관성을 지켜내고, rollback과 commit하는 일은 비용이 큰 작업들이다. 이에, trade-off 들로 다양한 lock 전략들이 나왔다.
Mysql은 이러한 전략들을 isolation level 로 나누어 두었다.
phantom read:
- 하나의 transaction 안에서 첫 query와 그 다음 동일한 쿼리의 결과가 다른 경우.
- non-repeatable read와 달리, 첫 query의 row에 lock을 걸어도 다른 row가 수정되어 두번 째 query의 조건에 만족될 수 있기 때문에 방지하기 어려움
- isolation level 중에서는 serializable read에서만 방지됨
실제 여러 transaction이 동일한 데이터에 update와 insert를 하는 상황을 두고 어떤 방식으로 해결할지 고민해볼 예정이다.
django transaction: django 공식문서
isolation level: mysql 공식문서
READ COMMITTED:mysql 공식문서
READ UNCOMMITED: mysql 공식문서
REPEATABLE READ: mysql 공식문서
SERIALIZABLE: mysql 공식문서
phantom read: mysql 공식문서