SQLAlchemy 도 Spring의 Transaction 처럼 read-only 를 만드는 기능이 있는지 물어보는 질문이 있었습니다. 이 글의 답변에도 작성했지만, 저도 SpringBoot 를 사용할때는 Transaction 격리수준, 전파수준 등을 엄청 신경썼었는데 FastAPI&SQLAlchemy 를 사용하면서 한번도 이런 고민을 안했습니다.
이게 개별 비즈니스 로직을 간단하게 유지할 수밖에 없는 프레임워크의 장점아닌 장점이라고 생각하면서 SQLAlchemy 에서 read-only transaction 을 만드는 방법을 알아보았습니다.
Does SQLAlchemy automatically create a transaction for read-only operations?
I am currently learning backend development using FastAPI + SQLAlchemy, and I have a question regarding transaction handling in SQLAlchemy. While reading the official SQLAlchemy documentation, I came
stackoverflow.com
해결방법
왠만한 고민에 대한 해답은(특히 소프트웨어 개발 영역에서) 인터넷에 있기 마련입니다. 보통 stackoverflow 에 질문을 올리는 사람들은 인터넷에서 답을 찾지 못한 경우가 많은데 이번 질문은 github issue 를 찾아봤다면 답을 알 수 있는 질문이었습니다.
SQLAlchemy issue 에 비슷한 질문이 있었고, maintainer 는 공식적으로 read-only transaction 을 만드는 방법이 제공되진 않지만 SQLAlchemy 에서 제공하는 events 를 이용해서 충분히 구현이 가능합니다.
from sqlalchemy import create_engine, Column, Integer, String, event
from sqlalchemy.orm import Session, sessionmaker, declarative_base
# Define the base and ORM model.
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
def __repr__(self):
return self.name
# Utility functions to mark a session as read-only.
def set_read_only(session: Session, read_only: bool = True):
session.info['read_only'] = read_only
def is_read_only(session: Session) -> bool:
return session.info.get('read_only', False)
# Listen for before_flush event and prevent flushing if session is read-only.
@event.listens_for(Session, "before_flush")
def before_flush(session, flush_context, instances):
if is_read_only(session):
raise Exception("Read-only session: flush not allowed")
# Setup the database and create a session.
if __name__ == "__main__":
engine = create_engine("sqlite:///:memory:")
SessionLocal = sessionmaker(bind=engine)
# Create tables.
Base.metadata.create_all(engine)
# Get Session
session = SessionLocal()
# normal Session ()
new_user = User(name="Alice")
session.add(new_user)
users = session.query(User).all()
print("Users:", users)
session.commit()
# read-only Session ()
set_read_only(session, True) # Mark session as read-only
new_user = User(name="James")
session.add(new_user)
users = session.query(User).all()
print("Users:", users)
session.commit()
Spring 에서는 read-only Transaction 을 만들어서 약간의 성능상 이점을 얻을 수도 있었지만, SQLAlchemy 에서는 그런 성능상 이점을 기대할 수 있을지는 모르겠습니다.
'탐구 생활 > 개발 탐구' 카테고리의 다른 글
티스토리 스킨 hELLO 에 기여해보기 (0) | 2025.02.19 |
---|---|
FastAPI & Postgres 로 multi-tenancy 구현하기 (0) | 2025.02.17 |
테이블 파티셔닝 적용기 (2) | 2024.02.13 |
Java, SpringBoot 에서 Geometry 좌표 핸들링 (2) | 2024.02.09 |
AWS AutoScaling 수평 확장시 어플리케이션 자동 세팅 (2) | 2024.02.09 |