# 트랜잭션과 쿼리 실행하기
# 연결 얻기
다음처럼 데이터베이스에 연결하여 쿼리를 실행할 수 있습니다.
>>> from sqlalchemy import text
>>> with engine.connect() as conn:
... result = conn.execute(text("select 'hello world'"))
... print(result.all())
[('hello world',)]
engine.connect()
으로Connection
(opens new window) 객체를 얻어conn
에 담습니다.- 이
Connection
객체를 통해 데이터베이스와 상호작용할 수 있습니다. with ...
구문은 하나의 트랜잭션 단위가 됩니다.
- 이
- 트랜잭션은 자동으로 커밋되지 않습니다.
Connection.commit()
을 호출해야 커밋됩니다.
# 변경 사항 커밋하기
연결을 얻고, 트랜잭션을 연 뒤 데이터베이스와 상호작용하는 일들은 자동으로 커밋되지 않습니다.
커밋을 하려면 다음처럼 Connection.commit()
을 호출해야 합니다.
>>> with engine.connect() as conn:
... # 테이블을 생성합니다.
... conn.execute(text("CREATE TABLE some_table (x int, y int)"))
... # 데이터를 삽입합니다.
... conn.execute(
... text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
... [{"x": 1, "y": 1}, {"x": 2, "y": 4}]
... )
... # 위 변경사항을 커밋합니다.
... conn.commit()
위 코드의 실행하면 다음과 같은 결과가 출력됩니다.
BEGIN (implicit)
CREATE TABLE some_table (x int, y int)
[...] ()
<sqlalchemy.engine.cursor.CursorResult object at 0x...>
INSERT INTO some_table (x, y) VALUES (?, ?)
[...] ((1, 1), (2, 4))
<sqlalchemy.engine.cursor.CursorResult object at 0x...>
COMMIT
Engine.begin()
으로 트랜잭션 종료시 자동으로 커밋을 찍게할 수도 있습니다.
>>> with engine.begin() as conn:
... conn.execute(
... text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
... [{"x": 6, "y": 8}, {"x": 9, "y": 10}]
... )
... # 트랜잭션 (컨텍스트 구문)이 끝나면 커밋됩니다.
위 코드의 실행하면 다음과 같은 결과가 출력됩니다.
BEGIN (implicit)
INSERT INTO some_table (x, y) VALUES (?, ?)
[...] ((6, 8), (9, 10))
<sqlalchemy.engine.cursor.CursorResult object at 0x...>
COMMIT
# 명령문 실행의 기초
다음처럼 쿼리를 실행하고 그 결과를 받아올 수 있습니다.
>>> with engine.connect() as conn:
... # conn.execute() 는 Result라는 객체에 내보냅니다.
... result = conn.execute(text("SELECT x, y FROM some_table"))
... for row in result:
... print(f"x: {row.x} y: {row.y}")
x: 1 y: 1
x: 2 y: 4
x: 6 y: 8
x: 9 y: 10
Result
(opens new window) 객체는conn.execute()
가 반환해주는 "쿼리 결과"를 들고 있는 객체입니다.- 링크를 눌러보면 어떤 기능을 제공하는지 볼 수 있습니다.
- 예를 들면
Result.all()
을 통해Row
(opens new window) 객체의 리스트를 받을 수 있습니다.
Result
와Row
모두 sqlalchemy에서 제공하는 객체입니다.
Result
객체로 다음처럼 각 행에 액세스할 수 있습니다.
result = conn.execute(text("select x, y from some_table"))
# 튜플로 접근합니다.
for x, y in result:
# ...
# 정수 인덱스로 접근합니다.
for row in result:
x = row[0]
# 속성 이름으로 접근합니다.
for row in result:
y = row.y
# 매핑 액세스로 접근합니다.
for dict_row in result.mappings():
x = dict_row['x']
y = dict_row['y']
# 쿼리에 매개 변수 전달하기
쿼리에 다음처럼 파라미터를 전달할 수 있습니다.
>>> with engine.connect() as conn:
... result = conn.execute(
... text("SELECT x, y FROM some_table WHERE y > :y"), # 콜론 형식(:)으로 받습니다.
... {"y": 2} # 사전 형식으로 넘깁니다.
... )
... for row in result:
... print(f"x: {row.x} y: {row.y}")
x: 2 y: 4
x: 6 y: 8
x: 9 y: 10
다음처럼 여러 개의 매개 변수를 보낼수도 있습니다.
>>> with engine.connect() as conn:
... conn.execute(
... text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
... [{"x": 11, "y": 12}, {"x": 13, "y": 14}] # 사전의 리스트로 넘깁니다.
... )
... conn.commit()
위 코드는 다음과 같은 쿼리를 실행하게 됩니다.
INSERT INTO some_table (x, y) VALUES (?, ?) [...] ((11, 12), (13, 14))
"명령문으로 매개 변수 묶기" (opens new window) 가 공식 문서에 나오지만, 이 부분은 저도 이해가 되지 않아 넘기겠습니다.
추후 이해하신 분은 이 문서에 기여해주시면 감사하겠습니다.
# ORM Session
으로 실행
이번에는 Connection
객체가 아니라 ORM에서 제공해주는 Session
로 쿼리를 실행해봅시다.
다음처럼 해볼 수 있습니다.
>>> from sqlalchemy.orm import Session
>>> stmt = text("SELECT x, y FROM some_table WHERE y > :y ORDER BY x, y").bindparams(y=6)
>>> # Session 객체에 Engine 객체의 인스턴스를 넘겨 데이터베이스와 상호작용할 수 있는 인스턴스를 얻습니다.
>>> with Session(engine) as session:
... # Session.execute() 메서드로 쿼리를 실행합니다.
... result = session.execute(stmt)
... for row in result:
... print(f"x: {row.x} y: {row.y}")
Session
역시 종료 시에 자동으로 커밋을하지 않습니다. 커밋을 하려면 다음처럼 직접 Session.commit()
을 호출해야 합니다.
>>> with Session(engine) as session:
... result = session.execute(
... text("UPDATE some_table SET y=:y WHERE x=:x"),
... [{"x": 9, "y":11}, {"x": 13, "y": 15}]
... )
... session.commit() # 명시적으로 호출해야 합니다.