
SQLAlchemy๋ Python ๊ฐ์ฒด๋ก ์์
ํ๋ฉด, ๋ด๋ถ์์ SQL์ ์๋ ์์ฑํด DB์ ๋ํํ๊ฒ ๋ง๋ ๋ค.
์ฆ, โ๊ฐ์ฒด์งํฅ ์ธ๊ณโ์ โ๊ด๊ณํ DB ์ธ๊ณโ ์ฌ์ด์ ๋ฒ์ญ(๋งคํ)์ ์๋ํํ๋ค.
| ๊ตฌ๋ถ | ์ง์ SQL | ORM (SQLAlchemy) |
|---|---|---|
| ์ฟผ๋ฆฌ ์์ฑ | SQL ๋ฌธ์์ด์ ์ง์ ์์ฑ | Python ์ฝ๋(๋ชจ๋ธ/์ฟผ๋ฆฌ ๊ฐ์ฒด)๋ก ์์ฑ |
| ๊ฒฐ๊ณผ ํํ | ํํ/๋์ ๋๋ฆฌ | Python ๊ฐ์ฒด |
| ๋ณ๊ฒฝ ๋์ | DB ๊ต์ฒด/์คํค๋ง ๋ณ๊ฒฝ ์ ์์ ๋ ํผ | ์ฐ๊ฒฐ ๋ฌธ์์ด/๋ชจ๋ธ ์ค์ฌ์ผ๋ก ๋์ |
ํ๋ฆ๋
[Python App]
|
v
+-------------------+
| Engine (DB ์ฐ๊ฒฐ) | create_engine("...")
+-------------------+
|
v
+-------------------+
| Session (๋ํ์ฐฝ๊ตฌ) | Session(engine)
+-------------------+
|
v
+-------------------+
| Model (ํ
์ด๋ธ ๋งคํ) | class User(Base): ...
+-------------------+
|
v
+-------------------+
| CRUD + Commit/RB | add/get/select/delete
+-------------------+
ํต์ฌ ๊ด์ฐฐ ํฌ์ธํธ โ
โข Engine์ โDB๋ก ๊ฐ๋ ๊ธธโ
โข Session์ โDB์ ๋ํํ๋ ์ฐฝ๊ตฌโ์ด์ โ๋ณ๊ฒฝ์ฌํญ์ ๋ชจ์๋๋ ์์
๋โ
โข Model์ โํ
์ด๋ธ โ ํด๋์คโ ๋งคํ ๊ท์น
โข commit()์ด ์คํ๋๋ ์๊ฐ INSERT/UPDATE/DELETE๊ฐ ์ค์ ๋ก ๋ฐ์๋จ
ํ์ ํจํค์ง
โข SQLAlchemy (ORM)
โข DB ๋๋ผ์ด๋ฒ (MySQL/MariaDB๋ฉด PyMySQL ๋ฑ)
pip install sqlalchemy pymysql
์ฐ๊ฒฐ ๋ฌธ์์ด์ ์ด๋ฐ ํํ๋ค.
DB์ข
๋ฅ+๋๋ผ์ด๋ฒ://์ฌ์ฉ์:๋น๋ฐ๋ฒํธ@ํธ์คํธ:ํฌํธ/DB์ด๋ฆ
"mysql+pymysql://root:1234@localhost:3306/mydb",
| ์์ ์กฐ๊ฐ | ์๋ฏธ |
|---|---|
mysql+pymysql |
MySQL + PyMySQL ๋๋ผ์ด๋ฒ ์ฌ์ฉ |
root:1234 |
๊ณ์ /๋น๋ฐ๋ฒํธ |
localhost:3306 |
ํธ์คํธ/ํฌํธ |
mydb |
DB ์คํค๋ง ์ด๋ฆ |
์ฃผ์ โ ๏ธ
๋น๋ฐ๋ฒํธ๋ฅผ ์ฝ๋์ ๋ฐ์๋๋ฉด ๋ฐ๋ก ์ฌ๊ณ ๋ก ์ด์ด์ง๋ค.
.env / OS env / Secrets Manager ๋ฑ์ผ๋ก ๋ถ๋ฆฌํ๋ ์ต๊ด์ด ์ค์!
DB๋ MySQL/MariaDB ๊ธฐ์ค์ด๊ณ , DB๋ช /๊ณ์ /๋น๋ฒ์ ํ๊ฒฝ์ ๋ง๊ฒ ๋ฐ๊ฟ์ผ ํ๋ค.
# sqlalchemy_basic.py
# SQLAlchemy ๊ธฐ๋ณธ ํ๋ฆ: Engine -> Base/Model -> Session -> CRUD
# ์คํ ์ :
# pip install sqlalchemy pymysql
from datetime import datetime
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, select
from sqlalchemy.orm import declarative_base, Session
# ============================================================
# 1) Engine: DB๋ก ๊ฐ๋ "์ฐ๊ฒฐ ํต๋ก"
# ============================================================
# echo=True : SQLAlchemy๊ฐ ์์ฑํ SQL์ ์ฝ์์ ์ฐ์ด์ค๋ค (ํ์ต ์ ์ ์ฉ)
# pool_pre_ping=True : ์ฃฝ์ ์ปค๋ฅ์
์ ์๋ ๊ฐ์ง (์ค๋ฌด์์ ๊ฝค ๋์๋จ)
engine = create_engine(
"mysql+pymysql://root:1234@localhost:3306/mydb",
echo=True,
pool_pre_ping=True,
)
# ============================================================
# 2) Base: ๋งคํ ์๋ํ์ ์ถ๋ฐ์
# ============================================================
# Base๋ฅผ ์์๋ฐ๋ ํด๋์ค๋ "ํ
์ด๋ธ๊ณผ ์ฐ๊ฒฐ๋ ํ๋ณด"๊ฐ ๋๋ค
Base = declarative_base()
# ============================================================
# 3) Model: ํ
์ด๋ธ์ ํด๋์ค๋ก ์ ์
# ============================================================
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(String(50), nullable=False)
email = Column(String(255), unique=True, nullable=False)
is_active = Column(Boolean, default=True, nullable=False)
created_at = Column(DateTime, default=datetime.now, nullable=False)
def __repr__(self):
return f"User(id={self.id}, username='{self.username}', email='{self.email}')"
# ============================================================
# 4) ํ
์ด๋ธ ์์ฑ: ๋ชจ๋ธ -> ์ค์ DB ๋ฐ์
# ============================================================
# create_all()์ "์์ ๋๋ง" ๋ง๋ ๋ค
# ์คํค๋ง ๋ณ๊ฒฝ(์ปฌ๋ผ ์ถ๊ฐ/์์ /์ญ์ )์ ๋ณดํต Alembic ๊ฐ์ ๋ง์ด๊ทธ๋ ์ด์
๋๊ตฌ๋ก ํ๋ค
Base.metadata.create_all(engine)
# ============================================================
# 5) Session: DB์ ๋ํํ๋ ์ฐฝ๊ตฌ + ๋ณ๊ฒฝ์ฌํญ์ ๋ชจ์ผ๋ ์์
๋(Unit of Work)
# ============================================================
# ํต์ฌ:
# - add()/delete()๋ "์์ฝ"์ ๊ฐ๊น๋ค
# - commit()์์ ์ค์ ๋ก INSERT/UPDATE/DELETE๊ฐ ๋ฐ์๋๋ค
# - ์์ธ ๋ฐ์ ์ rollback()์ด ์์ ๋ฒจํธ๋ค
def main():
# -----------------------------
# Create (INSERT)
# -----------------------------
with Session(engine) as session:
try:
user = User(username="jay", email="jay@example.com")
session.add(user)
# flush๋ "DB์ SQL์ ๋ณด๋ด PK๋ฅผ ๋ฐ์์ค๋ ๋จ๊ณ"๊น์ง ์ํํ ์ ์๋ค
# commit ์ ์ user.id๊ฐ ํ์ํ ๋ ์ ์ฉํ๋ค
session.flush()
print("์์ฑ๋ PK:", user.id)
session.commit()
except Exception as e:
session.rollback()
raise e
# -----------------------------
# Read (SELECT)
# -----------------------------
with Session(engine) as session:
# 1) PK๋ก ๋จ์ผ ์กฐํ
found = session.get(User, 1)
print("PK ์กฐํ:", found)
# 2) ์กฐ๊ฑด ์กฐํ (SQLAlchemy 2.0 ์คํ์ผ)
stmt = select(User).where(User.username == "jay")
user_jay = session.scalars(stmt).first()
print("์กฐ๊ฑด ์กฐํ:", user_jay)
# 3) ์ ์ฒด ์กฐํ
stmt_all = select(User)
users = session.scalars(stmt_all).all()
print("์ ์ฒด ์กฐํ:", users)
# -----------------------------
# Update (UPDATE)
# -----------------------------
with Session(engine) as session:
try:
target = session.get(User, 1)
if target:
target.username = "jay_edited"
# ๋ณ๊ฒฝ ๊ฐ์ง๋ SQLAlchemy๊ฐ ํ๋ค (dirty tracking)
session.commit()
print("์์ ์๋ฃ:", target)
else:
print("์์ ๋์ ์์")
except Exception as e:
session.rollback()
raise e
# -----------------------------
# Delete (DELETE)
# -----------------------------
with Session(engine) as session:
try:
target = session.get(User, 1)
if target:
session.delete(target)
session.commit()
print("์ญ์ ์๋ฃ:", target)
else:
print("์ญ์ ๋์ ์์")
except Exception as e:
session.rollback()
raise e
if __name__ == "__main__":
main()
add()๋ ๊ณง๋ฐ๋ก INSERT๊ฐ ์๋๋ผ โ์ธ์ ์์ ๋์ ์ฌ๋ ค๋๋ ํ์โ๋ค.
session.add(user)
=> [Session ์์
๋]์ user๊ฐ ์ฌ๋ผ๊ฐ (์์ง DB ๋ฐ์ X)
session.flush()
=> INSERT SQL์ด ๋๊ฐ ์ ์์ (PK ํ์ํ ๋ ์ ์ฉ)
session.commit()
=> ํธ๋์ญ์
ํ์ , ์ค์ DB ๋ฐ์ O
์์ธ ๋ฐ์
=> session.rollback()์ผ๋ก ๋๋๋ฆผ
| SQL | SQLAlchemy | ์์ |
|---|---|---|
| INT | Integer | Column(Integer) |
| VARCHAR(n) | String(n) | Column(String(100)) |
| TEXT | Text | Column(Text) |
| BOOLEAN | Boolean | Column(Boolean, default=True) |
| DATETIME | DateTime | Column(DateTime, default=datetime.now) |
| FLOAT | Float | Column(Float) |
from sqlalchemy import Column, Integer, String, Boolean, DateTime
from datetime import datetime
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, autoincrement=True) # ์๋ ์ฆ๊ฐ
username = Column(String(50), nullable=False) # NOT NULL
email = Column(String(255), unique=True) # UNIQUE
is_active = Column(Boolean, default=True) # ๊ธฐ๋ณธ๊ฐ ์ค์
created_at = Column(DateTime, default=datetime.now) # ์์ฑ ์๊ฐ ์๋ ๊ธฐ๋ก
from sqlalchemy.orm import Session
# ๋ฐฉ๋ฒ 1: with ๋ฌธ ์ฌ์ฉ (๊ถ์ฅ)
with Session(engine) as session:
# ์์
์ํ
pass
# with ๋ธ๋ก ์ข
๋ฃ ์ ์๋์ผ๋ก session ๋ซํ
######################################
# ๋ฐฉ๋ฒ 2: ์ง์ ์์ฑ/์ข
๋ฃ
session = Session(engine)
try:
# ์์
์ํ
pass
finally:
session.close()
SQLAlchemy๋ โ๊ฐ์ฒด๋ก ์์ ํ๋ฉด SQL์ ๋ง๋ค์ด์ฃผ๋ ORMโ์ด๊ณ , ๊ธฐ๋ณธ ๋ผ๋๋ Engine โ Base/Model โ Session โ CRUD๋ค.
๋ค์ ํํธ์์ ๋ณดํต ์ด์ด์ง๋ ์ฃผ์ ๋ relationship(), lazy/eager loading, ์ธ์
์๋ช
์ฃผ๊ธฐ, ํธ๋์ญ์
์ ๋ต์ด๋ค.
์ด๊ฑธ ๋ฐฐ์ฐ๋ฉด โ์ (.) ์ ๊ทผ์ด ์ ์ํํ ์๋ ์๋์งโ๊ฐ ์์ ํ ์ ๋ฆฌ๋๋ค.