2015-12-23 3 views
2

Я попытался полностью разделить Flask и SQLAlchemy с помощью this method, но Flask все еще, кажется, способен обнаружить мою базу данных и начать новую транзакцию в начале каждого запроса.Как Flask запускает новую транзакцию SQLAlchemy в начале каждого запроса?

db.py файл создает новую сессию и определяет простую модель стола:

from sqlalchemy import create_engine 
from sqlalchemy.orm import scoped_session, sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import Column, String 


engine = create_engine("mysql://web:[email protected]/web_unique") 

print("creating new session") 
db_session = scoped_session(sessionmaker(bind=engine)) 

Base = declarative_base() 
Base.query = db_session.query_property() 


# define model of 'persons' table 
class Person(Base): 
    __tablename__ = "persons" 
    name = Column(String(30), primary_key=True) 

    def __repr__(self): 
     return "Person(\"{0.name}\")".format(self) 

# create table 
Base.metadata.create_all(bind=engine) 

И app.py, простое приложение Колба с помощью сеанса SQLAlchemy и модель:

from flask import Flask, escape 
app = Flask(__name__) 


# importing new session 
from db import db_session, Person 

# registering for app teardown to remove session 
@app.teardown_appcontext 
def shutdown_session(exception=None): 
    db_session.remove() 


@app.route("/query") 
def query(): 
    # query all persons in the database 
    all_persons = Person.query.all() 
    print all_persons 
    return "" # we use the console output 


if __name__ == "__main__": 
    app.run(debug=True) 

Бежим это:

$ python app.py 
creating new session 
* Running on http://127.0.0.1:5000/ 
* Restarting with reloader 
creating new session 

Вейдер достаточно ru нс db.py два раза, но мы просто игнорировать это, давайте доступ к веб-странице /query:

[] 
127.0.0.1 - - [23/Dec/2015 18:20:14] "GET /query HTTP/1.1" 200 - 

Мы можем видеть, что наш запрос ответили, что мы используем только консольный вывод. Там нет в базе данных нет Person еще, давайте добавим один:

mysql> INSERT INTO persons (name) VALUES ("Marie"); 
Query OK, 1 row affected (0.11 sec) 

Marie является частью базы данных сейчас, чтобы мы перезагрузить страницу:

[Person("Marie")] 
127.0.0.1 - - [23/Dec/2015 18:24:48] "GET /query HTTP/1.1" 200 - 

Как вы можете видеть сеанс уже знает о Marie , Фланец не создал новый сеанс. Это означает, что началась новая транзакция. Сравните это с примером плана python ниже, чтобы увидеть разницу.

Мой вопрос в том, как Flask может начать новую транзакцию в начале каждого запроса. Флакон не должен знать о базе данных, но, похоже, может что-то изменить в своем поведении.


В случае, если вы не знаете, что сделка SQLAlchemy считывают этот пункт, извлеченный из Managing Transactions:

Когда транзакционный состояние завершается после отката или фиксации, высвобождает сессии все транзакции и ресурсы подключения, а возвращается в состояние «начать», которое снова вызовет новое соединение и объекты Транзакции, так как новые запросы на выдачу операторов SQL получат .

Таким образом, транзакция завершается фиксацией и создаст новое соединение, которое затем сделает сеанс снова прочитанным в базе данных.На самом деле это означает, что вы должны совершить, если вы хотите, чтобы увидеть изменения, внесенные в базу данных:

Первый в интерактивном режиме Python:

>>> from db import db_session, Person 
creating new session 
>>> Person.query.all() 
[] 

коммутатора к MySQL и вставить новый Person:

mysql> INSERT INTO persons (name) VALUES ("Paul"); 
Query OK, 1 row affected (0.03 sec) 

Наконец попытаться загрузить Paul в нашей сессии:

>>> Person.query.all() 
[] 
>>> db_session.commit() 
>>> Person.query.all() 
[Person("Paul")] 
+1

'db.py' запускается два раза [из-за перегружателя] (http://stackoverflow.com/a/25504196/978961). – dirn

ответ

1

Я думаю, что проблема здесь в том, что scoped_session несколько скрывает то, что происходит с фактическими сеансами в использовании. Когда обработчик демонтажа

# registering for app teardown to remove session 
@app.teardown_appcontext 
def shutdown_session(exception=None): 
    db_session.remove() 

проходит в конце каждого запроса, вы звоните db_session.remove(), который распоряжается сессии, используемой в этом конкретном запросе наряду с любым контекстом транзакции. См http://docs.sqlalchemy.org/en/latest/orm/contextual.html для деталей, в частности

The scoped_session.remove() метод сначала вызывает Session.close() на текущей сессии, который имеет эффект высвобождения какие-либо подключения/транзакционные ресурсы, принадлежащие сессия первые , затем , отбрасывая сам сеанс. «Освобождение» означает, что соединения возвращаются в пул соединений, а любое транзакционное состояние - откатом , в конечном счете с использованием метода rollback() базового соединения DBAPI .

+0

Спасибо, что указали, что на самом деле я думал, что 'teardown_appcontext' будет вызываться только тогда, когда приложение отключится. Но, как вы сказали, это также работает в конце каждого запроса. – timakro

Смежные вопросы