일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 500
- Spring
- Troubleshooting
- AWS EC2
- Github Actions
- linux
- github
- EC2
- RDS
- AWS
- axios
- React
- springboot
- js
- macbook
- Java
- MongoDB
- TypeScript
- javascript
- MUI
- error
- nodejs
- docker
- python
- Jenkins
- Express
- webhook
- deploy
- fastapi
- ngrok
- Today
- Total
BEAT A SHOTGUN
[MongoDB] transaction 본문
시작
질문과 답변을 등록하는 데에 다양한 방법이 있지만,
가끔
여러 이유로 답변 데이터를 생성하면서 답변 데이터에 질문id를 포함하고, 동시에 질문 데이터에 답변id도 추가하도록 하고 싶을 때가 있다.
그래서
insert_answer_result =
await mongodb.answer.insert_one({
"question_id": question_id,
**answer_data
...
})
update_question_result =
await mongodb.question.update_on(
{"question_id": question_id},
{"$addToSet": {"answers": answer_id}}
)
이렇게 할 때가 있다.
하지만
이렇게 하면, 답변 생성은 성공했지만 질문 업데이트는 실패하는 경우가 생길 수 있다.
그러면 데이터의 불일치가 발생한다. DB의 일관성이 떨어지고, 신뢰성이 떨어진다.
그럼 어떻게 하냐
sql을 공부하면 트랜잭션이라는 걸 배운다.
위와 같은 문제가 데이터의 일관성과 신뢰성을 헤치는 걸 막아주는 유용한 거다.
트랜잭션 내에 있는 작업 중 하나라도 완료되지 않고 에러가 발생하면 이전에 수행되었던 작업들도 모두 롤백되는 신기한 기능.
원리
정처기나 sql에서도 배우지만, 트랜잭션은 가지고 있는 모든 작업이 완료될 때까지는 commit
하지 않는다. 그래서 트랜잭션 내에 작업이 남아있다면 앞서 완료된 작업이 있더라도 임시 DB에만 적용되며, 만일 다른 사용자가 DB를 사용하고 있더라도 완료된 작업이 보이지는 않는다.
만일 하나의 예외라도 발생하면 abortTransaction을 통해 트랜잭션을 롤백한다. 모든 작업이 취소되어(완료했던 작업 포함) 트랜잭션 시작 이전의 상태로 되돌아가게 된다.
어머나, 마침 우리의 MongoDB는 트랜잭션을 지원하네?
써보자
client = AsyncIOMotorclient(MONGODB_URL)
session = await client.start_session()
try:
async with session.start_transaction():
insert_answer_result = await mongodb.answer.insert_one({
"question_id": question_id,
**answer_data
}, session=session)
answer_id = insert_answer_result.answer_id
update_question_result = await mongodb.question.update_one(
{"question_id": question_id},
{"$addToSet": {"answers":answer_id}},
session=session
)
if insert_answer_result is None or update_question_result != 0:
raise PyMongoError("실패")
# 어떤 결과 return
except PyMongoError as e:
# 어떤 에러 return
finally:
await session.end_session()
이렇게 하면 트랜잭션 내에서 수행하는 작업 중 하나라도 에러가 발생하면 raise
에러를 통해 롤백하게 된다.
에러에도
return
을 쓰면except
로 나가지 않아서 롤백이 안됩니다.
예외(except)가 발생해야abortTransaction
을 호출하기 때문에 raise를 통해 나가버려야 합니다.
명시적으로
abortTransaction
을 호출할 수도 있습니다. 예외가 발생하지 않아도 특정 상황에서 롤백하고 싶을 때 사용할 수 있습니다.
끝
이게 아니라면 우리는 답변이 어떤 질문에 등록되어 있는데, 답변에는 그 질문이 연결되어 있지 않은 채로 흘러가버려서 일관성 없는 DB가 완성된다. 짠!🎉
트랜잭션을 사용하면 조금 복잡하지만 매우 유용하며, DB 신뢰성이 높일 수 있다.
콱 🙂
'LEARNING' 카테고리의 다른 글
[Django] 소셜 로그인 - allauth (0) | 2023.07.02 |
---|---|
[Linux] 이 정도면 근본임? (1) | 2023.04.25 |
[Dart] flutter 를 위한 Dart 공부 1 (0) | 2023.04.23 |
[R] R 설치와 R 스튜디오 설치 및 간단 사용법 - R 의 시작 (0) | 2023.03.26 |
[FastAPI] main 에 때려박은 user 관련 API 분리하기(feat. FastAPI 공식 Docs) (0) | 2023.02.09 |