概要
SQLAlchemyのautoflushについて理解できてなかったので調査しました。
調査した時の各バージョン
- SQLAlchemy : 1.3.3
- MySQL : 8.0.16
modelの作成
シンプルなuser_listテーブルを作成しこのテーブルをSQLAlchemyから操作することでautoflushの挙動を確認します。
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
Base = declarative_base()
class User(Base):
__tablename__ = 'user_list'
id = Column('id', Integer, primary_key=True)
name = Column('name', String(100))
autoflushの検証①(autoflush=True)
autoflushをTrueにして動作検証してみます。autoflushの影響があるのはSessionクラスの"add"、"delete"メソッドを使った時やモデルのプロパティに書き込みをした時(update)ですが、とりえあずaddメソッドで検証してみます。
from sqlalchemy.orm import Session
from model import User
# ~ 中略 ~
session = Session(
bind = ENGINE,
autocommit = False,
autoflush = True)
#1 user_listテーブルのレコード数確認
user_list = session.query(User)
print(user_list.count()) # ⇒ "0"出力
#2 1レコード追加
user = User(id = 1, name = 'hoge')
session.add(user)
#3 user_listテーブルのレコード数確認
print(user_list.count()) # ⇒ "1"出力
上記のコードを実行した場合、autoflush=Trueにしていると自動でinsert文が実行されるので#3の時点で"1"と出力されます。但し、実際にinsert文が実行されるタイミングは#3の"user_list.count()"が実行された時です。(この挙動はflushの処理をできるだけ遅延させる為、だろうか?)
autoflushの検証②(autoflush=False、明示的にflush実行)
autoflushをFalseにして明示的にflushメソッドを呼ぶパターンで動作検証してみます。
from sqlalchemy.orm import Session
from model import User
# ~ 中略 ~
session = Session(
bind = ENGINE,
autocommit = False,
autoflush = False)
#1 user_listテーブルのレコード数確認
user_list = session.query(User)
print(user_list.count()) # ⇒ "0"出力
#2 1レコード追加
user = User(id = 1, name = 'hoge')
session.add(user)
session.flush() # 明示的にflushメソッドを実行(insert文が実行される)
#3 user_listテーブルのレコード数確認
print(user_list.count()) # ⇒ "1"出力
上記のコードを実行した場合、autoflush=Falseではあるが明示的に"session.flush()"を実行しているので、この場合も#3の時点で"1"と出力されます。但し、実際にinsert文が実行されるタイミングはautoflush=Trueの時と異なり"session.flush()"の時点です。
autoflushの検証③(autoflush=False、flush無し)
autoflushをFalseにしてflushメソッドを呼ばないパターンで動作検証してみます。
from sqlalchemy.orm import Session
from model import User
# ~ 中略 ~
session = Session(
bind = ENGINE,
autocommit = False,
autoflush = False)
#1 user_listテーブルのレコード数確認
user_list = session.query(User)
print(user_list.count()) # ⇒ "0"出力
#2 1レコード追加
user = User(id = 1, name = 'hoge')
session.add(user)
#3 user_listテーブルのレコード数確認
print(user_list.count()) # ⇒ "0"出力
上記のコードを実行した場合、autoflush=Falseで"session.flush()"も実行していないのでinsert文は実行されず、#3の時点ではレコードが追加されていないので"0"が出力されます。ではこの場合は"session.add()"がなかったことになるのかというとそういうわけでもなく、最終的に"session.commit()"してやればそのタイミングでinsert文は実行されます。
autoflushはTrue、Falseのどちらが良いか?
基本的にautoflush=Trueにしておいたほうがうっかりミスも発生せずコードもシンプルになり良さそうです。Sessionクラスのデフォルト値もautoflush=Trueですし。逆にautoflush=Falseにしたほうが良い場合が思いつかない。。(SQL実行のタイミングを明示的にしたい場合とか?)