home
Unit of work로 레거시 극복하기
- 기존의 레포지토리 레이어의 로직에는 각 SQL문에 한번씩
commit()
을 수행했다. - 이렇게 되면
session.begin()
이나session.begin_nested()
을 수행하더라도commit()
이 savepoint를 빠져 나가서 의미가 없어진다. - 그래서 생각한 것이 commit을 flag의 True False로 관리하면 되지 않을까? 였다.
class CustomSession(Session):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.skip_commit = False
def commit(self):
if self.skip_commit:
print("Commit skipped")
else:
super().commit()
- Session을 오버라이딩하여서 skip_commit이라는 플래그를 생성해준다.
- 그리고 skip_commit이 True일 때 커밋을 스킵하고 False이면 commit을 해준다.
- 그리고 Session을 만들 때 session maker에 해당 class를 지정해준다.
SessionLocal = sessionmaker(... , class_=CustomSession)
- skip을 위한 Unit of Work를 만들어준다.
class UnitOfWorkForSkip(AbstractUnitOfWork):
def __init__(self, db: Session):
self._db = db
def __enter__(self):
self._db.skip_commit = True
return self
def __exit__(self, *args):
print('rollback')
self._db.rollback()
self._db.close()
def commit(self):
try:
self._db.skip_commit = False
self._db.commit()
print('commit')
except SQLAlchemyError:
self.rollback()
raise TransactionFailException
def rollback(self):
self._db.rollback()
- 해당 UoW는
__enter__
시 skip_commit을 True로 하여서 컨텍스트 내부에서 일어나는 commit을 전부 스킵해준다. - 그리고
commit()
을 할 때 skip_commit 플래그를 다시 False로 바꿔줘서 실제 commit이 가능하게 만들어주고, commit을 진행한다. - 커밋도중 오류가 나면 rollback을 시키고 예외를 발생시킨다. 마찬가지로 컨텍스트에서 빠져나갈 때
commit()
을 명시하지 않았다면 rollback을 진행하고 세션을 종료시킨다. - 사용 예시는 다음과 같다
with UnitOfWorkForSkip(session) as uow
insertLogic1(session)
insertLogic2(session)
uow.commit()
- 이렇게 기존 코드에 적용하면 해당 skip uow를 사용하지 않은 코드들도 영향이 가지 않은 채로 레거시를 현명하게 대처할 수 있다.