<aside> 💡 세션 객체는 동시에 하나의 스레드의 한 트랜잭션 안에서만 공유되고 닫히는 방식으로 사용되어야 한다.
</aside>
'The
Session
is very much intended to be used in a non-concurrent fashion, which usually means in only one thread at a time.The
Session
should be used in such a way that one instance exists for a single series of operations within a single transaction. One expedient way to get this effect is by associating aSession
with the current thread (see Contextual/Thread-local Sessions for background). Another is to use a pattern where theSession
is passed between functions and is otherwise not shared with other threads.
create_engine()
QueuePool
echo = True
인 경우 쿼리문 관련 로그 찍힘echo_pool = True
인 경우 pool 관련 로그 찍힘pool_size
: pool에서 연결을 유지할 최댓값, 연결 요청 시 할당
QueuePool
, SingletonThreadPool
에서 사용NullPool
사용pool_recycle
: 설정 숫자만큼의 시간(초) 이후 pool이 recycle됨
max_overflow
: pool_size
를 초과한 연결 요청이 들어온 경우 추가적으로 허용되는 연결 수
QueuePool
인 경우 사용pool_size
에 맞게끔 연결 종료pool_timeout
: pool_size
+ max_overflow
를 초과한 요청이 들어온 경우, 설정 숫자만큼의 시간(초) 이후 커넥션 연결되지 못하면 포기
QueuePool
인 경우 사용Session
객체를 생성해주는 공장 역할
Session
객체는 thread safe하지 않은데, sessionmaker
로 생성 시 thread safe 하게 Session
사용 가능autocommit=True
인 경우 INSERT, UPDATE, DELETE, DDL 쿼리 발생하고, 트랜잭션이 진행중이지 않으면 flush 명령만 내려도 자동으로 커밋됨
False
session.begin()
과 session.commit()
(또는 rollback()
)을 명시해서 트랜잭션 사용 가능.begin()
이 나오기 전까지 autocommit
모드 활성화autocommit=False
권장
begin
상태) 이후 session.query()
나 session.execute()
작업 혹은 session.commit()
이나 session.flush()
로 플러쉬가 일어나면 쿼리가 수행되어 트랜잭션 시작begin
상태로 돌아감autoflush=True
인 경우 모든 쿼리 작업을 시작하기 전마다 Session.flush()
을 자동으로 해준다
True
autoflush
를 False
로 할때 주의사항
flush()
해주거나 autoflush
를 True
로 설정expire_on_commit
True
refresh()
하지 않아도 가장 최신 상태로 조회된다내부 레지스트리(딕셔너리)를 사용해 원하는 scope(보편적으로 request-local)에 한정된 세션 객체 제공
>>> from sqlalchemy.orm import scoped_session
>>> from sqlalchemy.orm import sessionmaker
>>> session_factory = sessionmaker(bind=some_engine)
>>> Session = scoped_session(session_factory)
# 같은 스코프 안에서는 같은 세션 객체 사용
>>> some_session = Session()
>>> some_other_session = Session()
>>> some_session is some_other_session
True
>>> Session.remove()
# 세션 객체를 다 사용하고 난 후에는 새로운 세션 객체 생성
>>> new_session = Session()
>>> new_session is some_session
False
Session = scoped_session(some_factory)
# equivalent to:
#
# session = Session()
# print(session.query(MyClass).all())
#
print(Session.query(MyClass).all())
디폴트로 thread local scope 레지스트리를 사용해 같은 스레드 내에서는 같은 세션 사용
method
sqlalchemy.orm.scoped_session.
init(session_factory, scopefunc=None)
- session_factory – a factory to create new
Session
instances. This is usually, but not necessarily, an instance ofsessionmaker
.- scopefunc – optional function which defines the current scope. If not passed, the
scoped_session
object assumes “thread-local” scope, and will use a Pythonthreading.local()
in order to maintain the currentSession
. If passed, the function should return a hashable token; this token will be used as the key in a dictionary in order to store and retrieve the currentSession
.
여러 리포지토리 메서드를 하나의 트랜잭션을 묶고 싶은 경우 용이
대표 사용 예시
In particular, while using a thread local can be convenient, it is preferable that the
Session
be associated directly with the request, rather than with the current thread
Web Server Web Framework SQLAlchemy ORM Code
-------------- -------------- ------------------------------
startup -> Web framework # Session registry is established
initializes Session = scoped_session(sessionmaker())
incoming
web request -> web request -> # The registry is *optionally*
starts # called upon explicitly to create
# a Session local to the thread and/or request
Session()
# the Session registry can otherwise
# be used at any time, creating the
# request-local Session() if not present,
# or returning the existing one
Session.query(MyClass) # ...
Session.add(some_object) # ...
# if data was modified, commit the
# transaction
Session.commit()
web request ends -> # the registry is instructed to
# remove the Session
Session.remove()
sends output <-
outgoing web <-
response
async_create_engine
, async_scoped_session
등 asyncio와 연동하여 비동기적으로 DB와 통신 가능