mongoose transaction

Q kim·2021년 1월 8일
2

MongoDB

목록 보기
6/7

Transaction은 복수개의 작업들을 고립된 상태로 진행하게 해줍니다. 쉽게 말하면, 복수개의 작업이 모두 성공했을 때만 성공하게 되고, 그중 하나라도 실패하게 되면 모두가 실패하게 됩니다. 실패된 뒤에는 transaction 작업 전의 상태로 되돌아가게 됩니다.

Check Check

  • MongoDB에서 transaction은 replica set에서만 가능합니다. stanlone에서는 불가능합니다. 어차피 실서비스에서는 replica set을 이용해야하니 신경쓰지 않으셔도 됩니다.
  • mongoose 버전이 5.2.0 이상이어야만 합니다!

Transaction은 MongoDB sessions에 구성되어 있습니다. startSession()호출한뒤 startTransaction() function을 호출하여야 트렌젝션을 시작할 수 있습니다. 트렌젝션 안에서 작업을 실행하려면 session을 옵션으로 전달해주어야만 합니다.

간단한 성공 트렌젝션 코드를 한번 볼까요.

const Account = db.model('Account', new Schema({ 
	onwer: String, 
	money: Number,
}));

await Account.create({ name: 'kim', money: 1000 });
await Account.create({ name: 'choi', money: 1000 });

await Account.insertMany([
		{ name: 'kim', money: 1000 }, 
		{ name: 'choi', money: 1000 }
	]
);

const session = await db.startSession();

session.startTransaction();

// kim의 계좌에서 인출
await Account.update({ name: 'kim' }, { $inc : { money: 100 } }, { new: true }).session(session);

// choi의 계좌에 송금
await Account.update({ name: 'choi' }, { $inc: { money: -100 } }, { new: true }).session(session);

await session.commitTransaction();

session.endSession();

위 코드에서 체크해야할 것은 몇가지 없습니다.
1. startSession() 으로 세션을 생성합니다.
2. session.startTransaction()을 통해 트렌젝션을 시작합니다.
3. DB 명령어들에 .session(session)을 붙여줍니다.(sessio 옵션을 설정합니다.)
4. session.commitTransaction() 모든 작업들을 commit(save changes)합니다.
5. session.endSession()을 통해 세션을 종료합니다.

이번에는 실패하는 세션을 살펴봅시다.

const session = await Account.startSession();
session.startTransaction();

await Account.create([{ name: 'Test' }], { session: session });
await Account.create([{ name: 'Test2' }], { session: session });

// abortTransaction() 메서드를 통해 rollback 시킵니다.
await session.abortTransaction();

const count = await Account.countDocuments();
assert.strictEqual(count, 0);

session.endSession();

abortTransaction() 메서드를 통해 트랜젝션내의 모든 작업을 rollback시킬 수 있습니다.

실패시 재시도
transaction에 에러가 발생하면, MongoDB 드라이버가 알아서 트렌젝션을 단 한번 재시도합니다.

withTransaction() helper

세션을 이용할 때 좀더 편하게 쓰려면 withTransaction()를 쓰세요 !

const session = await db.startSession();

session.startTransaction();

// kim의 계좌에서 인출
await Account.update({ name: 'kim' }, { $inc : { money: 100 } }, { new: true }).session(session);

// choi의 계좌에 송금
await Account.update({ name: 'choi' }, { $inc: { money: -100 } }, { new: true }).session(session);

await session.commitTransaction();

session.endSession();

위 코드를 아래코드로 줄여줍니다. startTransaction()과 commitTransaction() 코드를 한줄로 줄여줍니다.

const session = await db.startSession();

await session.withTransaction(() => {
	// kim의 계좌에서 인출
	await Account.update({ name: 'kim' }, { $inc : { money: 100 } }, { new: true }).session(session);

	// choi의 계좌에 송금
	await Account.update({ name: 'choi' }, { $inc: { money: -100 } }, { new: true }).session(session);
});


session.endSession();

.save()를 호출할 때는 session 옵션을 넣어줄 필요가 없습니다.

save() 메서드는 자동으로 관련된 session을 이용하도록 만들어져 있습니다.

profile
https://medium.com/nodejs-server

0개의 댓글