-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
68 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# unit of work로 레거시 극복하기 | ||
- 기존의 레포지토리 레이어의 로직에는 각 SQL문에 한번씩 `commit()`을 수행했다. | ||
- 이렇게 되면 `session.begin()`이나 `session.begin_nested()`을 수행하더라도 `commit()`이 savepoint를 빠져 나가서 의미가 없어진다. | ||
- 그래서 생각한 것이 commit을 flag의 True False로 관리하면 되지 않을까? 였다. | ||
|
||
``` python | ||
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를 지정해준다. | ||
|
||
```python | ||
SessionLocal = sessionmaker(... , class_=CustomSession) | ||
``` | ||
|
||
- skip을 위한 Unit of Work를 만들어준다. | ||
|
||
```python | ||
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을 진행하고 세션을 종료시킨다. | ||
- 사용 예시는 다음과 같다 | ||
|
||
```python | ||
with UnitOfWorkForSkip(session) as uow | ||
insertLogic1(session) | ||
insertLogic2(session) | ||
uow.commit() | ||
``` | ||
|
||
- 이렇게 기존 코드에 적용하면 해당 skip uow를 사용하지 않은 코드들도 영향이 가지 않은 채로 레거시를 현명하게 대처할 수 있다. |