flask_sqlalchemyでトランザクション処理

はじめに

 データベースにデータを追加したり削除したりといった操作をする場合、たいていは複数の操作をまとめて実行することが多い。

 例えば、あるネットショップのデータベースが「商品テーブル」「注文テーブル」「注文詳細テーブル」で構成されているとする。ある商品の注文が入ったら「注文詳細テーブル」に注文された商品や数量などを保存すると同時に、「商品テーブル」の在庫数を減らさなければならない。これがどれかの処理でエラーが発生し、途中で止まってしまったらどうなるか。注文は入ったけど在庫数が減らないなんていう事態が発生してしまう。これは絶対に避けたい。

 だからデータベースの処理は「すべての正常に変更し"確定"」か、「一個でもエラーが発生したらすべての変更を"破棄"」のどっちかでなけれなならない。このような処理をトランザクション処理という。

実装方法

流れ

トランザクション処理は下記により実装する。

with db.session.begin(subtransactions=True):
    # データベースへの分割不可な一連処理
db.session.commit()

以前の記事を参考にデータベースを作成し、操作するプログラムを実装する。

progmemo.hatenablog.jp

階層構造

MODEL_EXAM
  ├─app.py
  └─model_exam.sqlite

コード

# app.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__name__))
app.config['SECRET_KEY'] = 'mysecretkey'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'model_exam.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)

class Members(db.Model):
    __tablename__ = 'members'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text)
    age = db.Column(db.Integer)
    comment = db.Column(db.Text)

    def __init__(self, name, age, comment):
        self.name = name
        self.age = age
        self.comment = comment
db.create_all()  # テーブルの作成

# トランザクション処理
with db.session.begin(subtransactions=True):
    # データベースへの分割不可な一連処理
    new_member = Members("john", 29, "aaaabbbb")
    db.session.add(new_member)

db.session.commit()

参考にしたサイト

https://wa3.i-3-i.info/word16325.html

トランザクション管理とは?