Layers of Abstraction
Without SQLAlchemy
psycopg2와 같은 DBAPI 라이브러리가 데이터베이스와 상호작용한다.
하지만 이것은 파이썬을 사용하여 데이터베이스와 상호작용하는 가장 편리한 방법이 아닐 수도 있다.
With SQLAlchemy
SQLAlchemy는 데이터와 상호작용할 수 있는 다양한 layers of abstraction을 제공하기 때문에 그중에서 선택하여 이용할 수 있다.
SQLAlchemy vs psycopg2
- SQLAlchemy generates SQL statements.
- psycopg2 directly sends SQL statements to the database.
- SQLAlchemy는 데이터베이스와 통신하기 위해서 psycopg2나 다른 데이터베이스 드라이버들에 의존한다.
Layers of SQLAlchemy
- DBAPI
- The Dialect
- The Connection Pool
- The Engine
- SQL Expressions
- SQLAlchemy ORM(optional)
SQLAlchemy lets you traverse through all 3 layers of abstraction to interact with your database.
- ORM 레벨에 있을수도 있고
- Expression level에서 customized SQL code를 사용하여 데이터베이스에 접근할수도 있고
- Engine level에서 실행하기 위하여 raw SQL을 이용할 수도 있다.
The Dialect
우리가 raw SQL 대신 SQLAlchemy를 이용하는 이유 중에 하나가 우리가 어떤 데이터베이스를 사용하고 있는지 알지 않아도 된다는 점이었는데 이를 가능하게 해주는 것이 바로 Dialect이다.
- The dialect's layer controls the quirks and flavor of the specific database system that we're using.
The Connection Pool
- 존재하는 연결들을 쉽게 재사용할 수 있도록 해줌(더이상 수동으로 연결을 열고 닫지 않아도 됨)
- 매번 데이터 변화가 있을때마다 커넥션을 열고 닫는 것을 방지함
- 커넥션 문제 등에서 발생할 수 있는 dropped connection들을 다룸
- 매번 데이터에 변화가 생길때마다 계속적으로 발생하여 DB가 매우 느려질 수 있는 very many small calls를 방지
The Engine
- 데이터베이스와 상호작용 할 때 선택할 수 있는 3개의 메인 레이어들 중에 하나
- 데이터베이스와 상호작용하는 레이어들 중 가장 낮은 단계의 레이어. DBAPI를 사용할때와 매우 비슷한 방식이므로 psycopg2를 사용할때와 매우 유사하며 connection을 직접 관리함
- Engine은 자기자신, Dialect와 Connection pool을 모두 의미하고 데이터베이스와 상호작용할 때 모두 함께 작용한다.
- Connection pool은 우리가 SQLAlchemy engine을 생성하면 자동적으로 생성된다.
Example
from sqlalchemy import create_engine
engine = create_engine('postgres://..')
conn = engine.connect()
result = conn.execute('SELECT * ...')
row = result.fetchone()
rows = result.fetchall()
result.close()
SQL Expressions
- raw SQL을 직접 보내는 것(using the Engine) 대신 SQL expressions를 구성하기 위해 파이썬 객체들을 구성할 수 있다.
- SQL expressions는 데이터베이스와 상호작용하기 위하여 여전히 SQL을 알고있고 사용하는 것을 내포한다.
Example
todos = Table('todos', ...) ### 테이블 이름과 컬럼들
ins = todos.insert().values(
description = 'Clean my room',
completed = False
)
s = select([todos])
conn = engine.connect()
result = conn.execute(ins)
result = conn.execute(s)
result.close()
todos.c.description
-> <Column 'description' in 'todos' table>
SQLAlchemy ORM
- 파이썬 객체의 클래스들을 데이터베이스의 테이블에 맵핑함으로써 SQL expressions을 구성하도록 한다.
- SQLAlchemy의 layer of abstraction 중 가장 상위 레이어이다.
- SQL expression과 Engine이 데이터 베이스와 상호작용하기 위하여 함께 일할 수 있도록 둘을 묶는다.
Mapping Between Tables and Classes
앞서 ORM이 클래스를 테이블에 맵핑한다고 하였다. 어떤 식으로 맵핑되는지 살펴보자.
Classes
class Human:
def __init__(self, first_name, last_name, age):
self.fist_name = first_name
self.last_name = last_name
self.age = age
We can recall an object oriented prograaming and instantiating a class is very much like instantiating a collection of objects that could exist.
만약 우리가 Sarah와 Bob이라는 두 사람을 기록하고 싶다면
sarah = Human('Sarah', 'Silverman', 48)
bob = Human('Bob', 'Saget', 54)
와 같이 Human 클래스의 객체 인스턴스들을 만들 수 있다.
각 애트리뷰트들은 한 명의 사람을 정의한다.
Tables
CREATE TABLE humans (
id INTEGER PRIMARY KEY,
first_name VARCHAR,
last_name VARCHAR,
age INTEGER
);
위의 템플릿은 테이블에 존재하는 칼럼들의 타입을 명시하는데 이는 Human 클래스에 있는 에트리뷰트들의 타입과 같은 것이다.
동일한 클래스에서 생성된 다른 객체들이 다른 애트리뷰트를 갖고 있는 것은 관계형 데이터 베이스 시스템에서 각각 동일한 칼럼에 다른 값들이 존재하는 것과 매우 비슷한 과정이다.
- Tables map to classes.
- Table records map to class objects.
- Table columns map to class attribute.