sqlite3는 파이썬 표준 라이브러리에 포함된 경량 관계형 데이터베이스입니다. 이 치트시트는 sqlite3 기본 CRUD, 파라미터 바인딩, 트랜잭션 처리와 SQL 인젝션 방지 패턴을 정리합니다.
언제 이 치트시트를 보나?
- 간단한 로컬 데이터 저장이 필요할 때 (JSON/pickle보다 구조화된 쿼리가 필요할 때)
- SQL 문법은 아는데 파이썬 연동 방법이 헷갈릴 때
핵심 패턴
- 연결:
sqlite3.connect("db.sqlite3") → 파일 또는 :memory: - 쿼리 실행:
cursor.execute(sql, params) → 항상 파라미터 바인딩 사용 - 트랜잭션:
conn.commit() / conn.rollback() - 컨텍스트 매니저:
with conn: 블록 안에서 자동 commit/rollback
최소 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| import sqlite3
# 연결 (파일 또는 메모리)
conn = sqlite3.connect("example.db") # 또는 ":memory:"
cursor = conn.cursor()
# 테이블 생성
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE
)
""")
conn.commit()
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # INSERT - 파라미터 바인딩 (? 플레이스홀더)
cursor.execute(
"INSERT INTO users (name, email) VALUES (?, ?)",
("Alice", "alice@example.com")
)
conn.commit()
# INSERT 다건 - executemany
users_data = [
("Bob", "bob@example.com"),
("Charlie", "charlie@example.com"),
]
cursor.executemany(
"INSERT INTO users (name, email) VALUES (?, ?)",
users_data
)
conn.commit()
|
1
2
3
4
5
6
7
8
9
| # SELECT - fetchone / fetchall
cursor.execute("SELECT * FROM users WHERE name = ?", ("Alice",))
row = cursor.fetchone() # 한 건 또는 None
print(row) # (1, 'Alice', 'alice@example.com')
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall() # 리스트
for row in rows:
print(row)
|
1
2
3
4
5
6
7
| # UPDATE / DELETE
cursor.execute(
"UPDATE users SET email = ? WHERE name = ?",
("alice_new@example.com", "Alice")
)
cursor.execute("DELETE FROM users WHERE name = ?", ("Charlie",))
conn.commit()
|
1
2
3
4
5
| # 컨텍스트 매니저로 자동 commit/rollback
with sqlite3.connect("example.db") as conn:
cursor = conn.cursor()
cursor.execute("INSERT INTO users (name, email) VALUES (?, ?)", ("Dave", "dave@example.com"))
# 블록 끝에서 자동 commit (예외 발생 시 rollback)
|
1
2
3
4
5
6
| # Row 객체로 컬럼명 접근
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE id = ?", (1,))
row = cursor.fetchone()
print(row["name"], row["email"]) # 컬럼명으로 접근
|
자주 하는 실수/주의점
- SQL 인젝션 방지: f-string이나 문자열 포맷으로 SQL 작성 금지 → 항상
? 플레이스홀더 사용1
2
3
4
5
| # BAD - SQL 인젝션 취약
cursor.execute(f"SELECT * FROM users WHERE name = '{name}'")
# GOOD - 파라미터 바인딩
cursor.execute("SELECT * FROM users WHERE name = ?", (name,))
|
- commit 누락: INSERT/UPDATE/DELETE 후
conn.commit() 호출 필수 (또는 with conn: 사용) - 단일 값 튜플: 파라미터가 하나일 때
(value,) 형태로 전달 (쉼표 필수) - 동시 접근: sqlite3는 파일 기반이라 동시 쓰기에 제한 있음 → 멀티스레드는
check_same_thread=False 필요 - 타입 매핑: sqlite는 동적 타입이라 파이썬 타입과 1:1 매칭되지 않을 수 있음
ORM 개념 (참고)
대규모 프로젝트에서는 SQLAlchemy 같은 ORM을 사용:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| # SQLAlchemy 예시 (설치 필요: pip install sqlalchemy)
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
engine = create_engine("sqlite:///example.db")
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# ORM CRUD
user = User(name="Eve", email="eve@example.com")
session.add(user)
session.commit()
|
관련 링크(공식 문서)