Session
은 SessionTransaction
객체를 사용해 단일 ‘가상’ 트랜잭션을 트래킹한다
SessionTransaction
객체가 Session
이 묶여있는 Engine
을 사용해 실제 커넥션 레벨의 트랜잭션 관리1.4 버전부터 ‘가상’ 트랜잭션은 명시적으로 Session.begin()
을 사용하거나, 명시하지 않아도 자동으로 시작됨
commit()
(혹은 rollback()
)이나 close()
로 닫힌다from sqlalchemy.orm import Session
session = Session(engine)
**# 1. 명시적 begin w/ context manager (자동 커밋 또는 롤백)**
with session.begin():
session.add(some_object())
session.add(some_other_object())
# commits transaction at the end, or rolls back if there
# was an exception raised
**# 1-1. 명시적 begin w/o context manager (명시적 커밋 또는 롤백)**
session.begin()
try:
item1 = session.query(Item).get(1)
item2 = session.query(Item).get(2)
item1.foo = "bar"
item2.bar = "foo"
session.commit()
except:
session.rollback()
raise
-----------------------------------------------------------------------
**# 2. 자동 begin w/o context manager (명시적 커밋 또는 롤백)**
session = Session(engine)
session.add(some_object())
session.add(some_other_object())
session.commit() # commits
# will automatically begin again
result = session.execute(< some select statement >)
session.add_all([more_objects, ...])
session.commit() # commits
session.add(still_another_object)
session.flush() # flush still_another_object
session.rollback() # rolls back still_another_object
**# 2-1. 자동 begin w/ context manager**
with Session(engine) as session:
session.add(some_object())
session.add(some_other_object())
session.commit() # commits
session.add(still_another_object)
session.flush() # flush still_another_object
session.commit() # commits
result = session.execute(<some SELECT statement>)
# remaining transactional state from the .execute() call is
# discarded
**# 2-2. 자동 begin w/ context manager & sessionmaker**
Session = sessionmaker(engine)
# 2-2-1
with Session() as session:
with session.begin():
session.add(some_object)
# commits
# closes the Session
# 2-2-2
with Session.begin() as session:
session.add(some_object):
트랜잭션이 커밋과 롤백이 보장되지 않은 경우 Session.close()
를 활용해 롤백과 커넥션 반납을 보장할 수 있다
# expunges all objects, releases all transactions unconditionally
# (with rollback), releases all database connections back to their
# engines
session.close()
<aside>
💡 아래 예시는 모두 context manager로 사용되고 있지만, 일반 함수와 같이 호출하고 명시적으로 close()
등의 후처리를 해주어도 된다
</aside>
connection.execute()
시점에 autobegin 특성으로 인해 트랜잭션이 자동 시작된다connection.commit()
혹은 connection.rollback()
선언 전까지 유효하다with engine.connect() as connection:
connection.execute(some_table.insert(), {"x": 7, "y": "this is some data"})
connection.execute(
some_other_table.insert(), {"q": 8, "p": "this is some more data"}
)
connection.commit() # commit the transaction
connection.execute()
이 실행되면 또 다른 트랜잭션이 자동 시작된다with engine.connect() as connection:
connection.execute(text("<some statement>"))
connection.commit() # commits "some statement"
# new transaction starts
connection.execute(text("<some other statement>"))
connection.rollback() # rolls back "some other statement"
# new transaction starts
connection.execute(text("<a third statement>"))
connection.commit() # commits "a third statement"
with engine.connect() as connection:
with connection.begin():
connection.execute(some_table.insert(), {"x": 7, "y": "this is some data"})
connection.execute(
some_other_table.insert(), {"q": 8, "p": "this is some more data"}
)
# transaction is committed
Connect and Begin Once from the Engine
engine.begin()
으로 engine.connect()
와 connection.begin()
을 한번에 선언 가능with engine.begin() as connection:
connection.execute(some_table.insert(), {"x": 7, "y": "this is some data"})
connection.execute(
some_other_table.insert(), {"q": 8, "p": "this is some more data"}
)
# transaction is committed, and Connection is released to the connection
# pool
engine.connect()
블록 내에서 “commit as you go”와 “begin once” 방식을 혼합해서 사용 가능InvalidRequestError
가 발생한다with engine.connect() as connection:
with connection.begin():
# run statements in a "begin once" block
connection.execute(some_table.insert(), {"x": 7, "y": "this is some data"})
# transaction is committed
# run a new statement outside of a block. The connection
# autobegins
connection.execute(
some_other_table.insert(), {"q": 8, "p": "this is some more data"}
)
# commit explicitly
connection.commit()
# can use a "begin once" block here
with connection.begin():
# run more statements
connection.execute(...)