CastleJo의 개발일지

pymysql 사용하기

|

pymysql

pymysql은 직관적으로 Python에서 mysql을 사용하기 위한 모듈이다.
많은 예제가 있고, 소스코드도 많지만 각자 코드를 쓰는 방식이 모두 다르다.
사용법은 가장 기본적으로만 쓰고, sql 쿼리문은 INSERT문 한개만 쓰겠다.
이 글은 나의 코딩 방식만을 위주로 쓸 방식이다.

Class 생성


import pymysql
from pymysql.connections import Connection

class MySQL:

    def __init__(self, user, passwd, host, db, charset='utf8'):
        self.__user = user
        self.__passwd = passwd
        self.__host = host
        self.__db = db
        self.__charset = charset
        self.__conn : Connection = None

        self.connect()

가장 기본적인 생성자이다.
Connection은 None으로 둔 상태로 둔다.
모든 멤버변수는 private 변수로 선언해준다.

    def connect(self):
        if self.__conn is None:
            self.__conn = pymysql.connect(
                            user = self.__user, 
                            passwd = self.__passwd,
                            host = self.__host,
                            db = self.__db,
                            charset = self.__charset)

    def disconnect(self):
        if self.__conn is not None:
            self.__conn.close()

connection 멤버변수에 실제로 연결 상태를 저장해둔다.
나는 singleton 패턴으로 사용하는것을 선호한다.

class Singleton:
    __instance = None

    @classmethod
    def __getInstance(cls):
        return cls.__instance
    
    @classmethod
    def instance(cls, *args, **kargs):
        cls.__instance = cls(*args, **kargs)
        cls.instance = cls.__getInstance
        return cls.__instance

class SingletonSQL(MySQL, Singleton):
    pass

생성할 때는
s = singletonSQL.instance(user, pw, host, db)
로 하면 되고 s = singletonSQL.instance() 로 인스턴스를 호출할 수도 있다.

파이썬의 상속 특성상 이중상속을 하면 A에서 있는 기능을 우선으로 상속한 뒤 남는 부분만 B에서 불러오므로, A 클래스에서 instance 함수를 구현하지만 않으면 된다.

    def insertTable(self, arg1, arg2, arg3, tableName = "status"):
        try:
            self.__insertStatus(arg1, arg2, arg3, tableName)
        
        except Exception as e:
            logger.error(e)
            logger.exception(e)
        

    def __insertStatus(self, arg1, arg2, arg3, tableName):
        cursor = self.__conn.cursor()
        # column: col1 : String, col2 : Integer, col3 : Float
        query = f"""
        INSERT INTO {tableName} (col1, col2, col3) 
        VALUES ("{arg1}",{arg2},{arg3})
        """
        cursor.execute(query)
        self.__conn.commit()

__insertTable 은 좀 더 낮은 레벨에서 쿼리문만을 처리하는 함수이고
insertTable 은 내부적으로 __insertTable을 호출하며 다른 추가적인 행동을 넣을 수 있는 포장된 함수이다.

문자열 포맷팅방식에서 s = f"문자열 {변수} " 방식은 파이썬 3.6 이후로 지원하는 방식인데, 문자열 포맷팅 방식 3가지중 가장 빠르고 편한 방식이다. 사용하자.

고민해본 점

GO 를 공부하다보니, 함수를 매개변수로 받는 방식도 꽤나 좋은 유연성을 제공한다고 생각한다.

또한 SQL의 쿼리 함수들은 모두 exception을 포장할 때가 많다.

함수로 인터페이스를 구현하고 인터페이스를 작동하는 한가지 함수로 묶어보는 것도 나쁘지 않을 것 같다고 생각된다.

다음에 한번 해봐야겠다.