add ORM.md

This commit is contained in:
jgcha 2025-05-09 23:02:47 +09:00
parent 177b9f2161
commit a2b942f8a2

View File

@ -0,0 +1,90 @@
---
published: true
layout: post
title: "ORM"
categories: [Database]
tags: [ORM]
---
<br>
프로젝트를 진행하면서 raw query 대신 orm을 사용하라는 말을 많이 들어왔다. 하지만 간단한 query의 경우 문제없이 작동하는 경우가 대다수였지만 query가 복잡해질수록 속도 문제가 발생하기 시작했다. 당시 많은 시행착오를 겪어가며 끝까지 orm으로 프로젝트를 마무리했지만 raw query를 썼다면 간단히 해결될 문제이기도 했다. 하지만 프로젝트는 협업이 중요하니 orm은 사용해야겠고 조금 더 자세히 알아보고자 한다
<br>
## ORM이란?
**ORM(Object-Relational Mapping)**은 객체 지향 프로그래밍 언어에서 데이터베이스와의 통신을 객체를 통해 할 수 있도록 해주는 기술
즉, 테이블은 클래스(Class)로, 레코드는 객체(Instance)로 매핑되며, SQL 쿼리를 작성하지 않고도 데이터를 처리 가능
## ORM의 장점
- **생산성**: SQL 문을 직접 작성할 필요 없이 객체를 통해 데이터베이스 조작 가능
- **유지보수성**: 데이터베이스와 Python 객체 간의 구조가 일치하여 코드 수정이 간편
- **보안성**: SQL Injection을 자동으로 방지
- **이식성**: 데이터베이스 시스템이 변경되더라도 ORM만 수정하면 되어 이식성이 높음
- **객체 지향적**: 코드가 객체 지향적으로 작성되어 가독성과 유지보수가 용이
## ORM의 단점
- **성능 저하**: 복잡한 쿼리나 대량의 데이터를 처리할 때 ORM이 성능 이슈를 유발할 수 있음
- **추상화의 한계**: 복잡한 SQL 쿼리는 ORM으로 작성하기 어려운 경우가 있음
- **학습 곡선**: ORM을 제대로 활용하려면 SQLAlchemy나 Django ORM 같은 도구의 개념을 이해해야 함
## Raw Query와 비교
| 항목 | Raw SQL | ORM |
|------|---------|-----|
| 작성 방식 | SQL 문자열 직접 작성 | Python 객체/메서드 사용 |
| 유지보수성 | 낮음 (SQL 변경 시 직접 수정) | 높음 (클래스 구조만 수정하면 됨) |
| 학습 곡선 | 낮음 (SQL만 알면 됨) | 높음 (ORM 프레임워크 이해 필요) |
| 유연성 | 매우 높음 (모든 SQL 표현 가능) | 제한적 (복잡한 쿼리는 어렵거나 비효율적) |
| 보안 | SQL 인젝션 위험 존재 | 대부분 자동 방어 |
| 속도 | 더 빠를 수 있음 (최적화된 쿼리 직접 작성 가능) | 약간 느릴 수 있음 (추상화로 인한 오버헤드) |
| 코드 양 | 많음 (CRUD 반복적) | 적음 (모델/메서드 중심) |
## SQLAlchemy
- SQLAlchemy는 파이썬의 대표적인 ORM 라이브러리
- 데이터베이스와의 상호작용을 객체 지향적으로 처리할 수 있게 해줌
## 주요 구성 요소
- **Base 클래스**: ORM 모델은 `declarative_base()` 함수를 사용하여 생성된 **Base 클래스**를 상속받음
- **세션 (Session)**: `Session` 객체는 데이터베이스와의 연결을 관리하고, 트랜잭션을 관리하며 데이터를 추가, 조회, 수정, 삭제하는 작업을 수행함
- **모델 (Model)**: ORM 모델은 데이터베이스 테이블을 나타내는 Python 클래스이며 클래스의 속성은 테이블의 컬럼에 매핑됨
```python
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, declarative_base, sessionmaker
# Base 클래스 생성
Base = declarative_base()
# User 모델 정의
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
# 관계 정의: 1:N (한 사용자는 여러 개의 주소를 가질 수 있음)
addresses = relationship("Address", back_populates="user")
# Address 모델 정의
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer, ForeignKey('users.id'))
# 관계 정의
user = relationship("User", back_populates="addresses")
# DB 엔진 생성
engine = create_engine('sqlite:///example.db', echo=True)
# 테이블 생성
Base.metadata.create_all(engine)
```