서론
Python은 Java에 비해 표준화된 ORM이나 SQL mapper 기술을 제공하고 있지 않으며, 외부 의존성이 이 역할을 대신하고 있다. Java의 경우, Hibernate와 MyBatis 등의 외부 의존성을 사용하지 않는 건 아니지만 JPA 또는 JDBC라는 표준을 제공하고 있어서 어느 정도 일관된 인터페이스를 제공하고 있으므로 외부 의존성의 교체가 나름 용이한 편이다. 그러나 Python은 표준화된 DB 인터페이스가 없어서 상당히 불편하며, 매번 새로운 라이브러리에 대해 학습해야 하고, 기존 코드를 변경해야 하는 부담이 발생한다.
Python의 DB 사용 전략
크게 ORM을 사용하는 방법과 DB connectivity(JDBC, ODBC 수준의 연결성을 의미함)를 사용하는 방법이 있다.
전자의 경우, SQLAlchemy가 단연 압도적인 비중을 차지하고 있으며, Tortoise ORM도 나름 쓸만하지만 막상 써보면 DBMS 타입에 따라 호환성 문제가 존재한다. Django ORM, Peewee, Pony ORM도 있다고 하는데 그냥 고민하지 말고 SQLAlchemy를 사용하자.
ORM
- SQLAlchemy
- https://docs.sqlalchemy.org/
- SQLAlchemy는 ORM 뿐만 아니라 당연하게도 mapper 스타일의 사용방법도 제공함
- asyncio에 기반하여 비동기 프로그래밍도 지원하고 있음
- Tortoise ORM
- https://tortoise.github.io/
- 비동기 지원
DB connectivity
DBMS 타입에 따라 상호 호환되지 않는 인터페이스를 제공한다.
SQLite
- sqlite3
- Python 기본 패키지
MySQL
- MySQLdb
- https://mysqlclient.readthedocs.io/user_guide.html
- 고성능
- Python 3.x에서 사용하려면 MySQL-Python 또는 mysqlclient를 사용해야 함
pip install mysqlclientimport MySQLdb
- MySQL Connector/Python
- PyMySQL
- https://pymysql.readthedocs.io/en/latest/
- Python 구현체라서 성능이 위 두 가지보다는 좀 떨어짐
- 비동기 지원하지 않음
- aiomysql
- https://aiomysql.readthedocs.io/en/stable/
- 비동기 지원
- 추상화하기 어려움
PostgreSQL
- psycopg2
- https://www.psycopg.org/
- 고성능
- 비동기 지원하지 않음
- asyncpg
ODBC
- pyodbc
- 범용성이 좋지만 그만큼 설정에 손이 많이 가는 편임
유의사항
만약 두 가지 DBMS에 동시에 접근하는 기능이 필요하다면 두 개의 별도 라이브러리를 도입해서 사용해야 한다. 전혀 다른 스타일의 코드가 두 벌이 필요하다. DBMS가 바뀌면 라이브러리도 바뀌고 기존 코드도 바뀐다. 당연히 개발 생산성이 좋을 리가 없다.
연결을 맺은 다음에, 그 연결 객체를 멀티 프로세스에 공유해서 사용하는 것은 문제가 생길 수 있으므로 연결 객체를 공유하는 대신에 연결 풀(connection pool)을 사용하는 게 바람직하다.
DB 접속 URL
- URL 구성
- Python에서 일반적으로 DB 접속 URL을 구성할 때 다음과 같은 일반적인 규칙이 있으며 DB 라이브러리에 따라 일부가 생략되기도 한다.
- scheme 부분을 제외하면 JDBC URL과 동일하다고 할 수 있다.
- ex) postgresql+psycopg2://scott:tiger@localhost:5432/mydatabase?ssl=true
- 이 예제를 보면서 구성 요소를 살펴보자.
- DBMS 타입(필수): postgresql
- DB 라이브러리: psycopg2
://(필수)- user ID: scott
- password: tiger
@- DB서버명: localhost
:- 포트번호: 5432
/- 데이터베이스명(필수): mydatabase
?- 옵션: ssl=true
SQLite
- 테스트용으로 메모리를 사용하는 경우
- sqlite:///:memory:
- sqlite:// 라고만 써도 위와 동일함
- 파일을 DB로 사용하는 경우
- sqlite:///파일이름
- ex) sqlite:///test.db (상대 경로)
- ex) sqlite:///home/user1/myproject/test.db (절대 경로)
Python의 기본 라이브러리인 sqlite3를 사용하는 경우에는 좀 더 생략해서 다음과 같이 사용한다.
- :memory:
- file::memory:
- file:DB파일경로
- DB파일경로
ORM을 사용하는 경우에는 sqlite://로 시작하는 URL을 사용한다.
from sqlalchemy import create_engine
engine = create_engine('sqlite:///example.db')
PostgreSQL
from sqlalchemy import create_engine
engine = create_engine("postgresql://myusername:mypassword@localhost:5432/mydatabase")
import pg8000
create_engine("postgresql+pg8000://myusername:mypassword@localhost:5432/mydatabase")
psycopg2가 기본 라이브러리이다.
MySQL
from sqlalchemy import create_engine
engine = create_engine("mysql://myusername:mypassword@localhost:3306/mydatabase")
import pymysql
engine = create_engine("mysql+pymysql://myusername:mypassword@localhost:3306/mydatabase")
import mysql.connector
engine = create_engine("mysql+mysqlconnector://myusername:mypassword@localhost:3306/mydatabase")
MySQLdb이 기본 라이브러리이다.