기록

Python으로 SQL 간단히 이용해보기 및 Drizzle이란

als982001 2025. 4. 26. 17:08

 

1. 개요

 이번에는 python과 javascript로 SQL을 이용하는 방법을 간단히 배워보았다. 그래서 이를 기록해보려고 한다.

 

2. Python에서 SQLite 사용하기

2-1. 기본 흐름

# 1. DB 연결
conn = sqlite3.connect("users.db")

# 2. 커서(Cursor) 가져오기
cur = conn.cursor()

# 3. 쿼리 실행
cur.execute("SELECT * FROM users")

# 4. 결과 가져오기
res = cur.execute("SELECT * FROM users")
all_movies = res.fetchall()

# 5. DB 반영
conn.commit()

# 6. DB 연결 종료
conn.close()
  • 결과 가져오기
    • fetchall(): 결과를 전부 가져옴
    • fetchmany(n): 결과를 n개 가져옴
    • fetchone(): 결과를 한 개 가져옴

 

2-2. 테이블 생성 및 데이터 삽입

2-2-1. 테이블 생성

cur.execute("""
CREATE TABLE users (
    user_id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT NOT NULL,
    password TEXT NOT NULL
);
""")

 

2-2-2. 여러 데이터 삽입

# 리스트 형태로 다중 삽입
data = [("lanna", 567), ("bora", 123)]
cur.executemany("INSERT INTO users (username, password) VALUES (?, ?)", data)

# 딕셔너리 형태로 다중 삽입
data = [{"name": "max", "password": 123}]
cur.executemany("INSERT INTO users (username, password) VALUES (:name, :password)", data)

 

2-3. SQL Injection 주의

def i_change_password(username, new_password):
    cur.execute(f"UPDATE users SET password = '{new_password}' WHERE username = '{username}'")

 

이처럼 문자열을 직접 끼워 넣는 방식은 SQL Injdection 공격 가능성이 있다.

 

def s_change_password(username, new_password):
    cur.execute("UPDATE users SET password = ? WHERE username = ?", (new_password, username))

 

?를 사용해서 값을 따로 전달하는 것으로 방지할 수 있다.

 

2-4. Redis를 이용한 캐싱

 자주 조회되는 데이터는 매번 DB를 조회하지 않고 Redis에 캐싱하는 것으로 빠르게 가져올 수 있다.

 

# Redis 연결
r = redis.Redis(host="localhost", port=6379, decode_responses=True)

# 캐싱 로직
def make_expensive_query():
    redis_key = "director:movies"
    cached_results = r.get(redis_key)

    if cached_results:
        print("cache hit")
        return json.loads(cached_results)
    else:
        print("cache miss")
        res = cur.execute("SELECT COUNT(*), director FROM movies GROUP BY director;")
        all_rows = res.fetchall()
        r.set(redis_key, json.dumps(all_rows), ex=20)  # 캐시 만료 시간 설정 (ex=20초)
        return all_rows

 

  1. 먼저 Redis에 캐시된 데이터가 있는지 확인
  2. 없으면 DB에서 쿼리 후 Redis에 저장
  3. 다음에는 Redis에서 바로 꺼내서 사용

 

2-5. fetch 관련 주의 사항

  • fetchall()을 먼저 쓰면 커서가 끝까지 이동하기에, 이후 fetchmany(), fetchone()을 써도 가져올 데이터가 없다.
  • 한 번 가져오면 커서는 앞으로 못 되돌린다. (필요하면 쿼리를 다시 실행해야 함)

 

2-6. 간단 정리

항목 배운 내용 요약
SQLite 연결 connect(), cursor(), execute(), fetch(), commit(), close()
데이터 삽입 executemany() 사용 가능
SQL Injdection 방지 ? 파라미터 바인딩 필수
Redis 캐싱 DB 결과를 Redis에 저장하고 재사용
커서 주의사항 fetchall() 이후에는 커서가 끝난다
캐시 만료 설정 set(key, value, ex=초)로 가능

 

2-7. cursor란

 cursor(커서)는 DB에 쿼리를 보내고, 결과를 가져오고, 조작하는 역할을 담당하는 객체이다. 2-1 코드에서 conn은 DB와 연결만 하는 것이라면, 커서는 DB에 명령을 날리고 결과를 주고 받는 것을 담당한다.

 

3. Drizzle

 Drizzle은 TypeScript 기반 ORM(Object-Relational Mapping) 라이브러리로, 데이터베이스를 타입 안정성 있게 다룰 수 있도록 도와주는 도구라고 할 수 있다. 

  • SQL을 직접 작성하는 대신, 코드로 테이블, 쿼리, 관계를 정의하고 조작할 수 있다.
  • 기존 ORM(예: Prisma, Sequelize)보다 훨씬 가볍고 직관적이다.
  • SQL을 타입 안전하게 만드는 방향에 가깝다.

 

3-1. Drizzle 특징

특징 설명
타입 안전성 TypeScript 타입을 활용해서 쿼리 작성 시 에러를 방지
투명한 SQL 생성 실제 생성되는 SQL을 쉽게 볼 수 있음
얇은 추상화 SQL을 숨기지 않고, 필요한 경우 직접 제어 가능
경량화 설치 용량이 가볍고, 실행 속도가 빠름
다양한 DB 지원 PostgreSQL, MySQL, SQLite 등을 지원
마이그레이션 지원 스키마 변경 관리 도구(drizzle-kit) 제공

 

3-2. Drizzle 사용 흐름

  1. DB 연결 생성
  2. 테이블 스키마 정의
  3. 쿼리 작성 및 실행
  4. 타입 안정성 유지하면서 결과 활용

 


관련 문서