概要
誤ったcommitの使用はトランザクションのACID特性を破綻させます。
ここでは実際に誤ったcommitの使い方によるACID特性の破綻を見ていきます。
トランザクションのACID特性が破綻する例
commit -> rollback -> commit
という動作を行いDBの内容がどうなるのか見ていきましょう。
commit -> rollback -> commit
engine = create_engine("mysql://user:password@db/test_db")
SessionClass = sessionmaker(engine, autoflush=False, autocommit=False)
session = SessionClass()
# commitで更新内容を確定
user = User(user_id="1", name="Johndoe", email="johndoe@example.com")
session.add(user)
session.commit()
# rollbackで更新内容を戻す
session.rollback()
# 再度commitで更新内容を確定
user = User(user_id="1", name="Johndoe", email="johndoe@example.com")
session.add(user)
session.commit()
上記のコードを実行すると以下のようなクエリが実行されます。
INSERT INTO user (id, name, email) VALUES ('1', 'Johndoe', 'johndoe@example.com')
COMMIT
ROLLBACK
INSERT INTO user (id, name, email) VALUES ('1', 'Johndoe', 'johndoe@example.com')
ROLLBACK
末尾のROLLBACKは直前のINSERTが失敗したことに対しての後処理としてシステムから呼ばれています。
また、pythonの実行ターミナルでは以下のエラーが発生します。
sqlalchemy.exc.IntegrityError: (MySQLdb.IntegrityError) (1062, "Duplicate entry '1' for key 'user.PRIMARY'")
1回目のcommitによりrollback不可な更新内容の確定が行われたため、
Primaryキーが同値のレコードをinsertするとエラーが発生します。
念の為にデータ更新ごとにcommitを行うという設計を行うと、
rollbackが出来なくなりACID特性を破綻させるという結果を招いてしまいます。
commitの使い方に関しては下記リンクを参照してみてください
SQLAlchemy flushとcommitの使い方