SQLAlchemy는 파이썬에서 가장 널리 사용되는 ORM(Object-Relational Mapping) 라이브러리로, 데이터베이스의 테이블을 파이썬 객체처럼 다룰 수 있게 해줍니다. 이 가이드에서는 SQLAlchemy ORM의 핵심 개념부터 실제 활용 방법까지 상세히 살펴봅니다.
환경 구성 및 설치
먼저 SQLAlchemy 라이브러리를 설치해야 합니다. 사용하는 데이터베이스에 따라 추가적인 드라이버 설치가 필요할 수 있습니다.
# SQLAlchemy 설치
pip install sqlalchemy
# 데이터베이스별 드라이버 (선택 사항)
# PostgreSQL: pip install psycopg2
# MySQL: pip install pymysql
데이터베이스 연결 설정
데이터베이스와 통신하기 위해 Engine 객체를 생성하고, 데이터 작업을 관리할 Session 객체를 설정합니다.
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# SQLite 데이터베이스 연결 설정 (파일 기반)
DATABASE_URL = "sqlite:///app_database.db"
engine = create_engine(DATABASE_URL, echo=True)
# 세션 생성을 위한 팩토리 설정
SessionManager = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 실제 데이터베이스 세션 인스턴스 생성
db_session = SessionManager()
데이터 모델 정의
데이터베이스 테이블과 매핑될 파이썬 클래스를 정의합니다. declarative_base를 상속받아 모델을 작성합니다.
from sqlalchemy import Column, Integer, String, ForeignKey, Text
from sqlalchemy.orm import relationship, declarative_base
Base = declarative_base()
class Member(Base):
__tablename__ = 'members'
uid = Column(Integer, primary_key=True, autoincrement=True)
username = Column(String(50), nullable=False, unique=True)
email = Column(String(100), nullable=False)
# 일대다 관계 설정
articles = relationship("Article", back_populates="writer")
class Article(Base):
__tablename__ = 'articles'
id = Column(Integer, primary_key=True)
subject = Column(String(200), nullable=False)
body = Column(Text)
writer_id = Column(Integer, ForeignKey('members.uid'))
# 다대일 관계 설정
writer = relationship("Member", back_populates="articles")
# 정의된 모델을 기반으로 실제 테이블 생성
Base.metadata.create_all(bind=engine)
기본적인 CRUD 작업
객체를 생성, 조회, 수정, 삭제하는 기본적인 데이터 조작 방법입니다.
# 데이터 생성 (Create)
new_member = Member(username="it_expert", email="dev@example.com")
db_session.add(new_member)
db_session.commit()
# 데이터 조회 (Read)
# 전체 목록 조회
all_members = db_session.query(Member).all()
# 특정 조건 조회
target_member = db_session.query(Member).filter(Member.username == "it_expert").first()
# 데이터 수정 (Update)
if target_member:
target_member.email = "new_contact@example.com"
db_session.commit()
# 데이터 삭제 (Delete)
# db_session.delete(target_member)
# db_session.commit()
고급 쿼리 및 필터링
복잡한 조건을 가진 데이터를 추출하기 위해 필터링과 정렬, 집계 함수를 사용할 수 있습니다.
from sqlalchemy import and_, or_, func
# 복합 조건 필터링
results = db_session.query(Member).filter(
and_(
Member.username.like("it%"),
Member.email.contains("example")
)
).all()
# 정렬 및 개수 제한
sorted_members = db_session.query(Member).order_by(Member.username.desc()).limit(5).all()
# 집계 함수 사용
total_count = db_session.query(func.count(Member.uid)).scalar()
print(f"전체 회원 수: {total_count}")
조인(Join)과 관계 활용
여러 테이블에 분산된 데이터를 연결하여 조회하는 방식입니다.
# 내부 조인(Inner Join)을 통한 게시글과 작성자 정보 조회
query_result = db_session.query(Article, Member).join(Member).filter(Member.username == "it_expert").all()
for article, member in query_result:
print(f"제목: {article.subject}, 작성자: {member.username}")
# 관계 속성을 이용한 접근 (Lazy Loading)
some_member = db_session.query(Member).first()
for art in some_member.articles:
print(f"회원이 작성한 글: {art.subject}")
트랜잭션 관리 및 컨텍스트 매니저
데이터의 일관성을 보장하기 위해 트랜잭션을 안전하게 관리하는 것이 중요합니다. 컨텍스트 매니저를 활용하면 효율적인 세션 관리가 가능합니다.
from contextlib import contextmanager
@contextmanager
def session_scope():
"""트랜잭션 생명주기를 관리하는 제너레이터"""
session = SessionManager()
try:
yield session
session.commit()
except Exception:
session.rollback()
raise
finally:
session.close()
# 사용 예시
with session_scope() as session:
article = Article(subject="SQLAlchemy 가이드", body="내용입니다.", writer_id=1)
session.add(article)
성능 최적화 팁
- Eager Loading: N+1 쿼리 문제를 방지하기 위해
joinedload등을 사용하여 연관 데이터를 한 번에 가져오십시오. - 연결 풀링:
create_engine호출 시pool_size와max_overflow파라미터를 조절하여 동시 접속 효율을 높이십시오. - 필요한 필드만 조회: 전체 객체 대신
session.query(Member.username)과 같이 필요한 컬럼만 지정하여 메모리 사용량을 줄이십시오.