Contextlib

2025. 11. 4. 20:01·python

sqlalchemy 를 사용하여 세션을 얻고 트랜잭션을 여는 흔한 코드는 다음과같다.

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import User

engine = create_engine("sqlite:///example.db", echo=True)
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)

def find_by_id(user_id: int):
    session = SessionLocal() # 세션 얻기
    try:
        session.begin() # 트랜잭션 시작
        user = session.query(User).filter(User.id == user_id).first()
        session.commit() # 커밋
        return user
    except Exception as e:
    	# 롤백이 필요한 비즈니스 익셉션 발생
        session.rollback()
        raise
    finally:
    	# 자원 반드시 닫기
        session.close()

 

아래의 finally 코드에 자원을 닫지않으면 커낵션 종료가 되지않아 커넥션풀에 세션이 반환되지 않아서 결국 언젠가 더이상 사용가능한 세션이 없어질 것이다.

 

그치만 사람이기에 휴먼에러가 발생하기 마련이고

지금의 코드는 간단한 try ~ except 라서 문제가 없지만 트랜잭션을 잘게 쪼게야 하는 상황이라던지 여러 try except 를 해야하는 상황이라면 내가 미쳐 finally 구문을 작성해서 자원을 반환하는지 잊기 마련이다.

 

물론 실제로 저렇게 명시적으로 try except 와 명시적인 rollback 까지는 잘 사용하지 않는다.

아래와 같은 코드가 sqlalchemy 를 사용할때 흔히볼 수 있는 코드패턴이다.

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import User

engine = create_engine("sqlite:///example.db", echo=True)
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)

def find_by_id(id: int):
    with SessionLocal() as session: # 세션 객체 얻기, close() 자동처리
        with session.begin():  # 트랜잭션 시작, commit()/rollback() 자동 처리
            user = session.query(User).filter(User.id == user_id).first()
			return user

 

with 절이 어떤것을 처리하기에 이가 가능한지 알아보려 한다.

with 과 context manager

우선 전지적 자바시점에서 보았을 때 비슷한 자원관리 패턴으로 try with resources 라는 문법이 있다.

이를 구현하기 위해서는 클래스가 AutoCloseable 인터페이스를 구현한 형태여야 했다.

 

파이썬도 이와 비슷하게 지원하듯 contextmanager 라는 방식이 있다.

클래스가 __enter__ 메소드와 __exit__ 메소드를 구현하고 있다면 

with 절이 시작할때 __enter__ 를 실행하고

with 절이 끝날때 __exit__ 을 실행한다.

class MyResource:

	def open(self):
    	print("myresource open")
    def close(self):
    	print("myresource close")

 # 위와 같은 자원이 있다고 가정했을 때,
 # with 절과 함께 사용함으로서 혹여나 생길 자원낭비를 막아주는것이 바로 contextmanger 이다.

class MyResource:

	def open(self):
    	print("myresource open")
    def close(self):
    	print("myresource close")
        
    def __enter__(self):
    	self.open()
        return self
    
    def __exit__(self):
    	self.close()
        
 # 그렇다고 매번 함수를 가서 인터페이스를 구현해주기 귀찮다면
 # contextlib 의 contextmanager 데코레이터와 제너레이터 함수를 통해 구현이 가능하다.
 
from contextlib import contextmanager

@contextmanager
def my_context():
    print("enter")
    yield "resource"      # __enter__() 의 반환값
    print("exit")         # __exit__() 의 정리 코드

 

다시 Sqlalchemy 의 Session 으로 넘어와서

그러면 sqlalchemy 에서 SessionLocal 은 engine 에 따른 새로만들어진 클래스이고

크게는 Session 클래스 타입이다.

즉, Session 클래스 내부적으로 __enter__ 와 __exit__ 이 있을수밖에 없다.

https://github.com/sqlalchemy/sqlalchemy/blob/a87faba35a65563447c8204cc47eb37ab47e216e/lib/sqlalchemy/orm/session.py#L1811-L1815

 

sqlalchemy/lib/sqlalchemy/orm/session.py at a87faba35a65563447c8204cc47eb37ab47e216e · sqlalchemy/sqlalchemy

The Database Toolkit for Python. Contribute to sqlalchemy/sqlalchemy development by creating an account on GitHub.

github.com

위 코드라인을 보면 자기자신 인스턴스를 반환하고,

__exit()__ 에서 철저하게 close()를 호출하고 있다.

 

session.begin() 을 통해 얻는 트랜잭션 인스턴스 또한 with 절이 가능하니까 다음과 같이 구현되어 있을 거다.

https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session.begin

 

Session API — SQLAlchemy 2.0 Documentation

Session API Session and sessionmaker() class sqlalchemy.orm.sessionmaker inherits from sqlalchemy.orm.session._SessionClassMethods, typing.Generic A configurable Session factory. The sessionmaker factory generates new Session objects when called, creating

docs.sqlalchemy.org

실제로도 session.begin() 을 통해 얻는 SessionTransaction 인스턴스는 파이썬 컨텍스트매니저 역할을 수행한다고 하니 내부적으로 .commit(), rollback() 또한 with 절로 가능하게 끔 인터페이스가 구현되어 있을것이다.

 

결론

자바에서의 try ~ with ~ resource 구절 자체는 with 절과 동일하며

해당 구문 혹은 구절이 사용가능하려면 대상 자원관리 클래스가 자바에서는 Autocloseable, 파이썬 기준으로 __enter__() 와 __exit__() 를 구현하고 있어야 한다.

 

 

 

 

'python' 카테고리의 다른 글

FastAPI Depends  (1) 2025.10.27
'python' 카테고리의 다른 글
  • FastAPI Depends
devKhc
devKhc
  • devKhc
    개발저장소 by 회창
    devKhc
  • 전체
    오늘
    어제
    • 분류 전체보기 (26)
      • Web-Spring (7)
      • CS (5)
      • Infra (3)
      • DB (1)
      • Java (3)
      • CodeTree (5)
      • python (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Multi-Processor
    __exit()__
    try with resources
    samesite=none
    __enter__()
    Springsecurity
    set-cookie
    모드비트
    인터럽트
    운영체제
    코딩테스트
    컨텍스트매니저
    다중 코어 시스템
    contextlib
    코드트리조별과제
    SpringBoot
    인터럽트 #운영체제 #공룡책
    코드트리
    이중모드와 다중모드
    defaultoauth2authorizationrequestresolver
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
devKhc
Contextlib
상단으로

티스토리툴바