Python 강좌 / MariaDB 연결과 트랜잭션 처리하기

Python에서 MariaDB를 사용할 때는 DB 드라이버로 연결하고 SQL과 값을 분리해 전달합니다. 이 실습은 순수 Python 드라이버 PyMySQL을 사용하며, SQLite와 달리 실행 중인 서버·DB·전용 계정이 필요합니다.

서버와 전용 실습 계정 준비

로컬 MariaDB 서버의 관리자 연결에서 아래 SQL을 실행합니다. 이름이 같은 DB나 계정이 이미 있다면 기존 용도를 확인하고 새 이름으로 바꿉니다. 예시 비밀번호는 실제 사용 값으로 교체하며 관리자 계정을 Python 코드에서 사용하지 않습니다.

관련 동작과 지원 조건은 MariaDB 연결과 트랜잭션 처리하기 관련 공식 문서에서 확인할 수 있습니다.

CREATE DATABASE python_lab CHARACTER SET utf8mb4;
CREATE USER 'python_app'@'127.0.0.1' IDENTIFIED BY 'replace-with-a-local-secret';
CREATE TABLE python_lab.expenses (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  external_id VARCHAR(64) NOT NULL UNIQUE,
  name VARCHAR(100) NOT NULL,
  amount BIGINT NOT NULL CHECK(amount >= 0)
) ENGINE=InnoDB;
GRANT SELECT, INSERT, UPDATE ON python_lab.expenses TO 'python_app'@'127.0.0.1';

계정·서버 준비가 처음이라면 MariaDB 강좌의 Python 연결·매개변수 쿼리 실습에서 SQL 관점의 권한·실패 검증을 함께 확인할 수 있습니다. 여기서는 Python 연결 수명과 예외 경로에 집중합니다.

드라이버 설치와 비밀값 전달

python -m pip install PyMySQL

현재 프로세스 환경에 MARIADB_USER와 MARIADB_PASSWORD를 설정합니다. 운영체제의 환경변수 설정이나 프로젝트의 비밀 관리 도구를 사용하고 값 자체를 소스·버전 관리·로그에 쓰지 않습니다. 셸 명령으로 입력하면 셸 기록에 남을 수 있다는 점도 고려합니다.

예제는 127.0.0.1의 로컬 서버용입니다. 원격 서버로 확장할 때는 서버 설정과 드라이버 옵션에 맞춰 CA·호스트 이름을 검증하는 TLS 연결을 구성합니다. 주소만 외부 서버로 바꾸고 기존 보안 조건이 유지된다고 가정하지 않습니다.

전체 연결·저장 코드

mariadb_demo.py 파일의 전체 내용입니다.

import os
import pymysql

con = pymysql.connect(
    host="127.0.0.1", port=int(os.environ.get("MARIADB_PORT", "3306")),
    user=os.environ["MARIADB_USER"], password=os.environ["MARIADB_PASSWORD"],
    database="python_lab", charset="utf8mb4", autocommit=False,
    connect_timeout=5, read_timeout=5, write_timeout=5,
)
try:
    try:
        with con.cursor() as cur:
            cur.execute("INSERT INTO expenses(external_id,name,amount) VALUES(%s,%s,%s) ON DUPLICATE KEY UPDATE name=VALUES(name), amount=VALUES(amount)", ("demo-1", "lunch", 8000))
        con.commit()
    except Exception:
        con.rollback()
        raise
    with con.cursor() as cur:
        cur.execute("SELECT name,amount FROM expenses WHERE external_id=%s", ("demo-1",))
        print(cur.fetchone())
finally:
    con.close()
python mariadb_demo.py

정상 실행하면 ('lunch', 8000)을 출력합니다. 같은 external_id를 갱신하므로 재실행해도 새 거래가 계속 추가되지 않습니다. 금액의 단위를 원으로 고정하고 실제 계정에는 필요한 테이블 권한만 부여했습니다.

매개변수와 트랜잭션 실패 확인

PyMySQL의 값 자리표시는 %s이며 Python 문자열 % 연산이나 f-string으로 값을 끼워 넣지 않습니다. %s는 문자열뿐 아니라 숫자에도 사용합니다. 테이블·열 이름은 값 매개변수가 아니므로 동적으로 고를 때는 허용 목록을 사용합니다.

  1. 잘못된 비밀번호로 연결 실패를 확인하고 원래 설정을 복구합니다.
  2. 금액을 -1로 바꾸어 DB 제약 오류와 롤백을 확인합니다.
  3. 권한을 줄인 계정에서 허용 작업과 거부 작업을 구분합니다.

connect 자체가 실패하면 con이 만들어지지 않습니다. 연결 이후에는 커서·트랜잭션·연결 종료를 별도로 관리합니다. rollback으로 DB 쓰기를 되돌릴 수 있어도 이미 수행한 외부 요청이나 파일 변경까지 되돌아가지는 않습니다.