나의 개발일지

[트러블 슈팅] pymysql 의 Cursor.execute() 파라미터값 설정 본문

Language/Python

[트러블 슈팅] pymysql 의 Cursor.execute() 파라미터값 설정

사각분무기 2024. 5. 14. 15:34

파이썬을 배우고 있습니다.

확실히 만만치가 않네요.

언어 자체는 자바에 비하면 크게 어려운 편은 아니지만 새로운 것을 배운다는 것은 쉽지 않더라구요.

문제

잔재미코딩이라는 강사님의 강의를 통해 학습을 하고 있습니다.

잔재미코딩님의 강의는 전반적으로 섬세하고 디테일한 설명이 강점이라고 생각합니다.

강의의 내용 하나하나가 유익하지만 개인적으로 커스터마이징을 하고 싶은 욕심이 생겨버렸습니다.

가령 pymysql을 활용한 db와의 통신 부분을 변형하고 싶었습니다.

우선 강사님의 코드는 아래와 같습니다.

@staticmethod
def get(user_id):
    mysql_db = conn_mysqldb()
    db_cursor = mysql_db.cursor()
    sql = "SELECT * FROM user_info WHERE USER_ID = '" + str(user_id) + "'"
    # print (sql)
    db_cursor.execute(sql)
    user = db_cursor.fetchone()
    if not user:
        return None

    user = User(user_id=user[0], user_email=user[1], blog_id=user[2])
    return user

아래는 저의 코드입니다.

@staticmethod
def get(user_id):
    mysql_db = conn_mysqldb()
    db_cursor = mysql_db.cursor()
    sql = 'select * from user_info where user_id = "%s"'
    # print(sql)
    db_cursor.execute(sql, (str(user_id)))
    user = db_cursor.fetchone()
    if not user:
        return None

    user = User(user_id=user[0], user_email=user[1], blog_id=user[2])
    return user

큰 틀은 다를 것이 없고 sql의 where 문에 사용할 인자를 execute를 통해 넣었다는 점이 다릅니다.

이를 통해 SQL Injection 을 방지하는 효과를 얻을 수 있다고 합니다.

하지만 user 객체가 제대로 반환되지 않았습니다.

원인

모든 곳을 한참 점검해보고 나서야 우선 sql 문이 문제인 것을 알았습니다.

강사님의 코드를 사용했을 경우엔 문제가 없다는 것 또한 확인했습니다.

그렇다면 문제는 sql 문에 있다는 뜻이지만 제가 작성한 sql문은 pymysql에서 제공하는 객체를 통해 사용됩니다.

고로 내부를 까보기로 했습니다.

Connection 객체 안의 Cursor 객체를 찾았습니다.

그리고 아래는 Cursor 객체 안의 execute 함수의 내용입니다.

def execute(self, query, args=None):
    while self.nextset():
        pass

    query = self.mogrify(query, args)

    result = self._query(query)
    self._executed = query
    return result

내부적으로 Cursor 객체 내의 _executed 라는 인스턴스 변수 안에 저장이 되는 것을 확인했습니다.

이를 바탕으로 print()를 찍어보겠습니다.

@staticmethod
def get(user_id):
    mysql_db = conn_mysqldb()
    db_cursor = mysql_db.cursor()
    sql = 'select * from user_info where user_id = "%s"'
    # print(sql)
    db_cursor.execute(sql, (str(user_id)))
    user = db_cursor.fetchone()

    print(db_cursor._executed)

    if not user:
        return None

    user = User(user_id=user[0], user_email=user[1], blog_id=user[2])
    return user


따움표가 한번 더 감싸지고 있었습니다.

해결

코드를 아래와 같이 수정함으로써 문제를 해결했습니다.

@staticmethod
def get(user_id):
    mysql_db = conn_mysqldb()
    db_cursor = mysql_db.cursor()
    sql = 'select * from user_info where user_id = %s'
    # print(sql)
    db_cursor.execute(sql, (str(user_id)))
    user = db_cursor.fetchone()
    print(db_cursor._executed)
    if not user:
        return None

    user = User(user_id=user[0], user_email=user[1], blog_id=user[2])
    return user

'Language > Python' 카테고리의 다른 글

파이썬 HashMap 직접 디자인하기 (ft. 개별 체이닝)  (2) 2025.04.11