flask_sqlalchemy 에서 db. session 은 요청 간 의 독립 을 어떻게 유지 하 는 지 - 소스 읽 기 노트
간단 한 예
# -*- coding:utf-8 -*-
from sqlalchemy.orm.session import Session #
from sqlalchemy.orm import scoped_session #
import time
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/mytest?charset=utf8'
db = SQLAlchemy(app) # db.init_app(app) app db , ,
db_session = db.session
class role(db.Model):
id = db.Column(db.INT, primary_key=True,autoincrement=True)
name = db.Column(db.String(99), unique=False)
name_cn = db.Column(db.String(99), unique=False)
def __init__(self, name, name_cn):
self.name = name
self.name_cn = name_cn
def __repr__(self):
return '' % self.name
# db.create_all()
@app.route('/add1')
def add1():
print("db.session:", vars(db_session))
print("id(db_session)",db_session)
test_role1 = role('supervisol', '11')
# test_role2 = role('your try', '11')
db_session.add(test_role1)
#db_session.add(test_role2)
#db.session.commit() #
time.sleep(60)
return "add1"
@app.route('/add2')
def add2():
print("db.session:",vars(db.session))
print("id(db_session)", db_session)
test_role1 = role('supervisol', '22')
#test_role2 = role('your try', '22')
db_session.add(test_role1)
#db_session.add(test_role2)
db_session.commit()
time.sleep(60)
return "add2"
if __name__ == '__main__':
app.run(threaded=True)
세 가지 run 방식.
# , socket, , 。(flask greenlet , , time.sleep )
# threaded , , 。
# processes 。
"""
root@(none):# date ;curl "http://127.0.0.1:5000/add2";date
Tue Aug 14 08:38:14 CST 2018
add2Tue Aug 14 08:39:14 CST 2018
root@(none):~# date ;curl "http://127.0.0.1:5000/add1";date
Tue Aug 14 08:38:16 CST 2018
add1Tue Aug 14 08:39:16 CST 2018
root@(none):~# ps -T -p 8657
PID SPID TTY TIME CMD
8657 8657 pts/7 00:00:00 python
8657 8662 pts/7 00:00:00 python
8657 8666 pts/7 00:00:00 python
"""
db. session 탐색
# db_session route , db_session
# flask_sqlalchemy.SQLAlchemy self.session = self.create_scoped_session(session_options)
# return orm.scoped_session(self.create_session(options), scopefunc=scopefunc)
# sqlalchemy.orm.session sqlalchemy.orm.scoped_session
# http://www.cnblogs.com/ctztake/p/8277372.html session id
# _app_ctx_stack.__ident_func__
# https://stackoverflow.com/questions/39480914/why-db-session-remove-must-be-called
# https://blog.csdn.net/yueguanghaidao/article/details/40016235
"""
# app sql
if app is not None:
self.init_app(app)
# , , session
@app.teardown_appcontext
def shutdown_session(response_or_exc):
if app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']:
if response_or_exc is None:
self.session.commit()
self.session.remove()
return response_or_exc
# sqlalchemy.orm.scoping.scoped_session
# sqlalchemy.util._collections.ScopedRegistry
def clear(self):
#Clear the current scope, if any.
try:
del self.registry[self.scopefunc()]
except KeyError:
pass
"""
바보 방법 print
# sqlalchemy.util._collections.ScopedRegistry id, session
('db.session:', {'session_factory': 127.0.0.1 - - [15/Aug/2018 15:48:19] "GET /add1 HTTP/1.1" 200 -
sessionmaker(class_='SignallingSession', autocommit=False, query_cls=, expire_on_commit=True, bind=None, db=, autoflush=True), 'registry': })
('id(db_session)', )
('1 __call__:', )
('2 __call__:', {})
('3 has:', {: })
('1 __call__:', )
('2 __call__:', {: })
('4 clear start:', {: })
('5 clear end:', {})
('db.session:', {'session_factory': sessionmaker(class_='SignallingSession', autocommit=False, query_cls=, expire_on_commit=True, bind=None, db=, autoflush=True), 'registry': })
('id(db_session)', )
('1 __call__:', )
('2 __call__:', {})
('1 __call__:', )
('2 __call__:', {: })
127.0.0.1 - - [15/Aug/2018 15:49:29] "GET /add2 HTTP/1.1" 200 -
('3 has:', {: })
('1 __call__:', )
('2 __call__:', {: })
('4 clear start:', {: })
('5 clear end:', {})
위의 절 차 를 총괄 하 다
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
포인트 가 왔 습 니 다.
sqlalchemy python orm , sqlalchemy django orm ,
flask sqlalchemy django 。
app.config['SQLALCHEMY_ECHO'] = True =》 sql
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True =》 request db.session.commit(),
db.session.add, db.session.commit, , 。
app.teardown_appcontext
@teardown
def shutdown_session(response_or_exc):
if app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']:
if response_or_exc is None:
self.session.commit()
self.session.remove()
return response_or_exc
response_or_exc , sys.exc_info()[1]
self.session.remove() self.session, ?
sqlalchemy session 。
from sqlalchemy.orm import sessionmaker
session = sessionmaker()
sessionmaker() session, session ,
,sqlalchemy scoped_session, scoped_session
session
from sqlalchemy.orm import scoped_session, sessionmaker
session = scoped_session(sessionmaker())
scoped_session
class scoped_session(object):
def __init__(self, session_factory, scopefunc=None):
self.session_factory = session_factory
if scopefunc:
self.registry = ScopedRegistry(session_factory, scopefunc)
else:
self.registry = ThreadLocalRegistry(session_factory)
__init__ ,session_factory session , sessionmaker ( __call__
) scopefunc , ThreadLocalRegistry
class ThreadLocalRegistry(ScopedRegistry):
def __init__(self, createfunc):
self.createfunc = createfunc
self.registry = threading.local()
def __call__(self):
try:
return self.registry.value
except AttributeError:
val = self.registry.v
__call__ , session, , __call__ ?
def instrument(name):
def do(self, *args, **kwargs):
return getattr(self.registry(), name)(*args, **kwargs)
return do
for meth in Session.public_methods:
setattr(scoped_session, meth, instrument(meth))
, session.query getattr(self.registry(), 'query'),self.registry()
__call__ , flask_sqlalchemy ThreadLocalRegistry, scoped_session
# Which stack should we use? _app_ctx_stack is new in 0.9
connection_stack = _app_ctx_stack or _request_ctx_stack
def __init__(self, app=None,
use_native_unicode=True,
session_options=None):
session_options.setdefault(
'scopefunc', connection_stack.__ident_func__
)
self.session = self.create_scoped_session(session_options)
def create_scoped_session(self, options=None):
"""Helper factory method that creates a scoped session."""
if options is None:
options = {}
scopefunc=options.pop('scopefunc', None)
return orm.scoped_session(
partial(_SignallingSession, self, **options), scopefunc=scopefunc
)
scopefunc connection_stack.__ident_func__, connection_stack flask app ,
__ident_func__ thrading.get_ident, id
ScopedRegistry _
class ScopedRegistry(object):
def __init__(self, createfunc, scopefunc):
self.createfunc = createfunc
self.scopefunc = scopefunc
self.registry = {}
def __call__(self):
key = self.scopefunc()
try:
return self.registry[key]
except KeyError:
return self.registry.setdefault(key, self.createfunc())
, id session , flask_sqlalchemy
, flask cookie,g , ?
1.flask_sqlalchemy ThreadLocalRegistry?
, wsgi greenlet
2. create_scoped_session partial ?
scoped_session session_factory , _SignallingSession __call__, partial
self.session.remove(), session
db.relationship lazy ,
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
users = db.relationship('User', backref='role', lazy='dynamic')
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
role Role
lazy:dynamic => role.users User , sqlalchemy.orm.dynamic.AppenderBaseQuery
role.users.all() sql,
lazy:select => role.users User , sql
:db.session.commit update
레 퍼 런 스
https://stackoverflow.com/questions/39480914/why-db-session-remove-must-be-called 문 제 를 야기 하 다.http://www.cnblogs.com/ctztake/p/8277372.html 모피https://blog.csdn.net/yueguanghaidao/article/details/40016235 사내 의 발자취http://docs.sqlalchemy.org/en/latest/orm/contextual.html#using- thread - local - scope - with - web - applications 문서
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.