지난 시간에는 PyMySQL의 멀티쓰레드 미지원으로 발생하는 문제를 살펴보았다.
관련해서 해결방법을 다른 분의 조언을 통해 아이디어를 얻어 재해결하는 방법을 만들어보았다.
먼저 조언을 받은 Connection Pool에 대한 내용을 짧게 요약해보고 가겠다.
Connection Pool이란 Was가 실행되면서 DB와 Connection을 연결해 놓은 객체를 Pool에 저장해 두었다가 클라이언트의 요청이 들어오면 이를 빌려주고 처리가 끝나면 반납하는 방식을 의미한다.

지난 번 해결책은 Thread별로 Connection을 사용할 때 Thread Lock을 걸어서 해결했는데 Thread별로 pool을 지정해주면 Thread의 병목 없이 해결할 수 있지 않을까? 라는 생각이 들었다.
지난번에 사용한 코드이다.
import pymysql
from threading import RLock
class Database():
def __init__(self):
self.LOCK = RLock()
self.db = pymysql.connect(host='',
user='',
db='',
password='')
self.cursor = self.db.cursor(pymysql.cursors.DictCursor)
def execute(self, query, args={}):
self.cursor.execute(query, args)
def executeOne(self, query, args={}):
with self.LOCK:
self.cursor.execute(query, args)
row = self.cursor.fetchone()
return row
def executeAll(self, query, args={}):
with self.LOCK:
self.cursor.execute(query, args)
row = self.cursor.fetchall()
return row
def commit(self):
self.db.commit()
이를 다음과 같이 바꿔보았다.
from pymysqlpool.pool import Pool
class Database():
def __init__(self):
self.db_config = {
"host" : "",
"port" : ,
"database" : "",
"password" : "",
"user" : ""
}
self.pool = Pool(**self.db_config)
self.pool.init()
def execute(self, query, args={}):
connection = self.pool.get_conn() #커넥션 풀에서 풀 가져오기
cursor = connection.cursor()
cursor.execute(query, args)
res = cursor.fetchall()
cursor.commit()
self.pool.release(connection) #커넥션 반환
return res
execute를 쓰레드가 호출 할 때 connection pool에서 pool을 가져와서 이를 사용하고 다시 pool을 connection pool로 반환하는 코드로 바꾸었다.
이렇게 처리를 하니 MultiThread로 인해서 발생하는 문제는 발생하지 않았다.
정리하자면
Thread가 pool을 공유함으로써 프로세스가 멀티쓰레드 상황에서 pymysql은 Thread Safe가 지원되지 않기 때문에 문제가 발생했다.
이를 해결하기 위해서 connection pool을 만들어 db와 통신할 때 pool을 쓰레드 별로 사용하게끔 하여 PyMySQL이 Thread Safe하지 않아서 발생하는 문제를 해결할 수 있었다.
읽어주셔서 감사합니다.
2개 포스팅 모두 너무 잘보고 갑니다 감사합니다!