Python DB 연결

이민재·2026년 4월 6일

Python DB 연결 - conn과 cursor 정리

PostgreSQL 기준으로 작성되었습니다.


conn이란?

conn데이터베이스와의 연결 자체를 담당하는 객체입니다.

self.conn = connection.Connection().postgresql_connection()

DB와의 통로 역할만 하며, SQL을 직접 실행하는 기능은 없습니다.


cursor란?

cursorconn을 통해 실제 SQL을 실행하는 객체입니다.

conn   = 은행 입장 (문)
cursor = 창구 직원 (실제 업무 처리)
with self.conn.cursor() as cursor:
    cursor.execute("SELECT * FROM users")
    result = cursor.fetchall()

cursor 주요 메서드

메서드설명
cursor.execute(sql)SQL 1개 실행
cursor.executemany(sql, list)SQL 여러 개 실행
cursor.fetchone()결과 1행 반환
cursor.fetchmany(n)결과 n행 반환
cursor.fetchall()결과 전체 반환
cursor.close()커서 닫기

cursor를 사용하는 이유

1. conn은 SQL 직접 실행 불가

self.conn.execute("SELECT * FROM users")          # ❌ 불가능
self.conn.cursor().execute("SELECT * FROM users") # ✅ 가능

2. 결과를 내부에 저장

cursor는 SQL 실행 후 결과를 내부에 임시 저장합니다.

DB 서버                cursor 내부
┌─────────┐           ┌──────────────┐
│ 100만 행 │  →SQL→   │ 결과 임시 저장 │ → fetchone()으로 하나씩
└─────────┘           └──────────────┘
cursor.execute("SELECT * FROM users")
cursor.fetchone()     # 1행 반환
cursor.fetchmany(100) # 100행 반환
cursor.fetchall()     # 전체 반환

3. 여러 작업을 독립적으로 처리

하나의 conn에서 여러 cursor를 동시에 운용할 수 있습니다.

cursor1 = self.conn.cursor()
cursor2 = self.conn.cursor()

cursor1.execute("SELECT * FROM users")   # 독립 실행
cursor2.execute("SELECT * FROM orders")  # 서로 영향 없음

result1 = cursor1.fetchall()
result2 = cursor2.fetchall()

4. 트랜잭션 관리

cursor 단위로 작업하고, conn으로 commit / rollback 합니다.

with self.conn.cursor() as cursor:
    try:
        cursor.execute("INSERT INTO users VALUES (%s)", ("Alice",))
        cursor.execute("INSERT INTO orders VALUES (%s)", (1,))
        self.conn.commit()    # 둘 다 성공 시 저장
    except:
        self.conn.rollback()  # 하나라도 실패 시 전부 취소

5. 메모리 효율

한 번에 모든 데이터를 가져오지 않고 필요한 만큼만 가져올 수 있습니다.

cursor.execute("SELECT * FROM users")  # 100만 행 조회

cursor.fetchone()      # ✅ 1행만 메모리에 올림
cursor.fetchmany(100)  # ✅ 100행만 메모리에 올림
cursor.fetchall()      # ⚠️ 100만 행 전부 메모리에 올림

with문과 함께 사용하는 이유

with 블록이 끝나면 자동으로 cursor.close()가 호출됩니다.

# with 없이
cursor = self.conn.cursor()
cursor.execute("SELECT * FROM users")
result = cursor.fetchall()
cursor.close()  # 직접 닫아야 함 ⚠️

# with 사용
with self.conn.cursor() as cursor:
    cursor.execute("SELECT * FROM users")
    result = cursor.fetchall()
# 자동으로 cursor.close() 호출 ✅

⚠️ with 사용 시 주의사항

cursorconn의 with 종료 시 동작이 다릅니다.

구문종료 시
with self.conn.cursor() as cursorcursor.close() 만 호출
with self.conn as connconn.close() 호출 ⚠️
self.conn = connection.Connection().postgresql_connection()

with self.conn.cursor() as cursor:
    cursor.execute("SELECT * FROM users")
# cursor만 닫힘, conn은 유지 ✅

print(self.conn.closed)  # 0 = 열림 ✅

self.connwith로 직접 감싸면 블록 종료 시 연결이 닫혀 재사용이 불가능합니다.

with self.conn as conn:  # ⚠️ 블록 끝나면 self.conn이 닫힘
    pass

# 이후 self.conn 재사용 불가! ❌

권장 패턴

self.conn을 여러 메서드에서 재사용하는 경우, cursor만 with로 관리하는 것이 좋습니다.

class UserService:
    def __init__(self):
        self.conn = connection.Connection().postgresql_connection()

    def get_users(self):
        with self.conn.cursor() as cursor:      # cursor만 with로 관리
            cursor.execute("SELECT * FROM users")
            return cursor.fetchall()
        # cursor 닫힘, conn 유지 → 재사용 가능 ✅

    def insert_user(self, name):
        with self.conn.cursor() as cursor:      # 같은 conn 재사용
            cursor.execute("INSERT INTO users VALUES (%s)", (name,))
            self.conn.commit()

    def close(self):
        self.conn.close()                       # 모든 작업 종료 후 명시적으로 닫기

전체 흐름 요약

conn 생성
  │
  ├── cursor 생성 (with)
  │     ├── execute() : SQL 실행
  │     ├── fetch()   : 결과 가져오기
  │     └── close()   : 자동 호출 (with 종료 시)
  │
  ├── commit() / rollback()  : conn이 담당
  │
  └── conn.close()  : 모든 작업 종료 후 명시적 호출
conncursor
역할DB 연결 유지SQL 실행
생성한 번만작업마다
with 종료 시연결 닫힘 ⚠️cursor만 닫힘 ✅
SQL 실행
profile
초보 개발자

0개의 댓글