IT·개발

Python pymysql로 MySQL에 로그 저장하기 — INSERT·commit 기본 패턴

5월 19, 2026 2 min read

2021년에 짧게 정리해뒀던 pymysql 기록을 2026년 기준으로 다듬어 올립니다. 원본 코드의 오타를 정정하고 실무 팁을 보완했습니다.

핵심 패턴부터 먼저 짚으면, Python에서 pymysql 4줄로 MySQL에 로그 한 줄을 INSERT 하고 commit() 한 번으로 저장이 끝납니다. 연결부터 INSERT까지 단계별로 아래에서 살펴보겠습니다.

당시 배경은 이렇습니다. 실제 운영 환경에서 자동화 스크립트 로깅에 직접 쓰던 코드인데, 파일 형식의 로그는 지정한 PATH에 직접 들어가야만 볼 수 있었습니다. SQL 문법도 공부할 겸, 쉬고 있는 DB 서버도 쓸 겸 해서 겸사겸사 로그를 DB로 보내는 튜닝을 했습니다.


1. 권장 환경

  • Python 3.x
  • pymysql 1.x 계열 기준
  • 설치: pip install pymysql

구체적인 패치 버전은 따지지 않겠습니다. 본 글 코드는 pymysql 1.x 계열 기준으로 동작합니다.

참고: PyPI · PyMySQL | GitHub · PyMySQL/PyMySQL


2. DB 연결 코드

다음 코드로 MySQL DB에 연결합니다.

import pymysql

db = pymysql.connect(
    user='id',
    passwd='pw',
    host='host',
    db='dbname',
    port='port',
    charset='utf8',
)

각 인자가 하는 역할입니다.

  • user — DB 접속 계정명
  • passwd — 비밀번호
  • host — DB 서버 주소
  • db — 접속할 데이터베이스명
  • port — 포트 번호 (정수형 int). 위 예시의 'port'는 placeholder이며, 실제 사용 시 정수 값을 입력하세요.
  • charset — 문자셋 (원본 기준 'utf8' 지정)

보안 팁 실무에서는 passwd='pw'처럼 코드에 자격증명을 평문으로 박지 않습니다. 환경변수(예: os.environ['DB_PASSWORD'])나 .env 파일에서 읽어오는 방식이 표준입니다. 본 글 예시는 단순화를 위해 placeholder 그대로 둔 것입니다.


3. 커서 생성

커서는 SQL을 DB에 전달하는 통로입니다. 아래처럼 생성합니다.

cursor = db.cursor(pymysql.cursors.DictCursor)

원본은 cusor로 표기되었으나 본 보완본에서는 표준 표기 cursor로 정정합니다.

pymysql.cursors.DictCursor는 쿼리 결과를 튜플이 아니라 컬럼명을 키로 쓰는 dict 형태로 돌려받게 해주는 커서입니다. result[0]['date']처럼 컬럼명으로 값을 바로 꺼낼 수 있어 코드 가독성이 높아집니다.

이제 커서까지 준비됐습니다. 이후부터는 이 커서로 SQL을 DB에 전달합니다.


4. SELECT 예시

연결이 정상인지 확인하거나 테이블 전체를 조회할 때 씁니다.

select_sql = "SELECT * from table_name;"
cursor.execute(select_sql)
result = cursor.fetchall()

cursor.execute(select_sql)로 쿼리를 실행하고, cursor.fetchall()로 결과 전체를 가져옵니다. result는 테이블의 모든 행이 담긴 리스트(DictCursor 사용 시 dict 리스트)입니다. 행이 많다면 fetchone()이나 fetchmany(N)으로 일부만 가져오는 방법도 있습니다.


5. INSERT + commit

로그를 DB에 저장하는 핵심 코드입니다. date, code, id, result 4개 컬럼에 값을 INSERT 합니다.

전제: MySQL에 date, code, id, result 컬럼을 가진 테이블(table_name)이 미리 생성되어 있어야 합니다. 테이블이 존재하지 않으면 INSERT가 동작하지 않습니다.

insert_sql = "INSERT into table_name(date, code, id, result) values(%s, %s, %s, %s)"
insert_val = (date, code, id, result)
cursor.execute(insert_sql, insert_val)
db.commit()

라인별로 짚어봅니다.

  • insert_sqldate, code, id, result 4개 컬럼에 값을 넣는 INSERT SQL. %s는 값이 들어갈 자리표시자입니다.
  • insert_val — 실제 들어갈 값을 튜플로 묶은 것입니다. date, code, id, result는 실제 저장할 로그 데이터를 담는 변수이며, 컬럼 구조를 보여주기 위한 자리표시자입니다. 실제 사용 시 각자 로그 데이터로 대체하면 됩니다.
  • cursor.execute(insert_sql, insert_val) — SQL과 값을 함께 전달해 실행합니다. pymysql이 insert_val의 값을 %s 자리에 끼워넣어 줍니다.
  • db.commit() — 변경사항을 실제로 DB에 반영합니다. 이게 빠지면 INSERT가 적용되지 않습니다.

%s 파라미터 바인딩이란

여기서 쓰인 %s는 Python의 단순 문자열 포맷(%s % value)과 다릅니다. pymysql이 값을 안전하게 이스케이프해서 SQL에 끼워넣어 주는 자리표시자입니다. f""+로 문자열을 직접 이어붙이는 방식보다 SQL Injection 위험이 줄어드는 효과가 있습니다. 완전한 방어라는 단정은 어렵지만, 직접 이어붙이기보다 훨씬 안전한 선택입니다.

데이터를 삽입하고 commit() 하고 끝입니다.


6. 5년 뒤 회고 — 지금이라면 챙길 것

이 아래는 팩트보다 제 개인 의견에 가깝습니다. 그 점 감안하고 읽어주세요.

2021년 코드를 다시 보면서 “지금이라면 함께 볼 것”으로 꼽히는 후보 세 가지입니다. 단정이 아니라 후보로만 적습니다.

연결 close 보장 — 원본 코드에는 db.close()가 없습니다. 연결이 닫히지 않으면 DB 커넥션이 열린 채 남습니다. 지금이라면 with 문이나 try/finally로 작업이 끝난 뒤 연결을 닫아주는 구조를 후보로 볼 것 같습니다. 이 글에서 상세 코드를 신설하지는 않지만, 장기 운영 환경이라면 함께 찾아볼 만한 주제입니다.

charset='utf8' vs utf8mb4 — 원본은 charset='utf8'입니다. 이모지나 4바이트 유니코드 문자까지 안전하게 저장하려면 utf8mb4가 현재 표준으로 통용됩니다. 당시 로그에 해당 문자가 없었다면 문제없었겠지만, 신규 프로젝트라면 utf8mb4를 후보로 검토해볼 만합니다.

자격증명 분리 — §2 보안 팁에서 언급했지만 한 번 더 강조합니다. 실제 운영 환경에서는 코드에 계정·비밀번호를 직접 쓰지 않는 것이 표준입니다. 환경변수나 시크릿 매니저로 빼는 방식을 처음부터 후보로 올려두면 좋습니다.


마치며

파일 로그도 좋지만, DB로 모아두면 SQL 한 줄로 날짜 필터·특정 코드 검색·집계가 가능해서 운영이 한결 가벼워집니다. 연결 → 커서 생성 → SELECT 확인 → INSERT + commit, 이 흐름 그대로 각 단계 코드를 복사해서 접속 정보만 바꿔 바로 쓸 수 있게 단계별로 정리했습니다. 단, MySQL에 해당 컬럼 구조의 테이블이 미리 존재하는 환경임을 전제합니다.


출처: 본 글은 2021-01-20 작성한 자체 실습 기록 — 「Python pymysql로 DB에 로그 저장하기 – INSERT, commit 기본 패턴」(원본 티스토리 post ID: 81) — 을 기반으로 2026년 보완한 것입니다.