MySQL을 다룰 때 매번 connection 객체를 생성하는 방식으로 사용하는 건 일반적인 방법이 아니다. 대규모 동시 접속을 수행할 경우에는 반드시 connection pooling이 필요한데, connection pool은 미리 일정 규모의 connection들을 만들어두고 사용하는 방식이며 max limit이 존재하므로 사용하고 난 뒤에 빠르게 connection 자원을 해제할 필요가 있다.
그러나 서비스 지속 시간이 길어질수록 예외가 발생하여 미처 connection을 해제하지 못해서 가용한 connection pool의 규모가 줄어들 위험성이 존재한다. 이런 경우에, Java의 try with resources 방법과 동일한 with ... as ... 문법을 사용하는 게 좋다.
Python에는 contextlib이 제공하는 contextmanager라는 기능이 있는데, file 핸들링에서 이것의 대표적인 사례를 볼 수 있다.
with open(filename, "r", encoding="utf-8") as infile:
infile.read()
with ... as ... 문법이 바로 contextmanager가 제공해주는 기능이다. with block이 종료할 때 자동으로 자원을 close해주는 등의 해제 작업을 수행한다.
파일 뿐만 아니라 다른 자원도 마찬가지로 해제가 가능하다. @contextmanager annotation을 이용하여 context를 관리해주면 된다.
DBManager라는 클래스에서 get_connection() 메소드를 제공한다고 가정한다. MySQL connection을 Connection() 클래스로 한 번 감쌌다.
from contextlib import contextmanager
class DBManager:
@contextmanager
def get_connection(self) -> Connection:
mysql_connection = self.pool.get_connection()
connection = Connection(mysql_connection)
try:
yield connection
finally:
connection.mysql_connection.close()
yield로 넘겨준 connection 자원을 finally 구문에서 close()를 호출하여 반드시 해제되도록 하고 있다.
with self.db_manager.get_connection() as connection:
self.db_manager.execute("INSERT INTO feed_alias_name VALUES (%s, %s)", feed_alias, feed_name)
self.db_manager.commit()