さるへい備忘録

さるへいのやったことを綴っているブログです。基本的にテクノロジーの話題です。

プログラムでtransactionをはったらcommitかrollbackで終わらせるようにしよう

みなさんtransaction使ってますか?transactionは便利で使う機会がとても多いと思います。 しかし皆さんちゃんとcommitとrollbackを設定していますか?
まぁセッションからコミットされない限りデータに変更ないしヘーキヘーキ!みたいなことを思ってる方もいるかもしれません。

しかしそれは危険です。僕はしっかり設計不備で危険を踏み抜きました。

以下に例を紹介します。

入れ子transaction

pythonっぽい疑似コードで示します。

def sample_inner():
    try:
        # トランザクション開始
        # コミット
    except Exception as e:
        pass

try:
    # トランザクション開始
    sample_inner()
    # コミット
except Exception as e:
    # ロールバック

上記のようなコードがあるとします。
こちら、 sample_inner() 内で例外が発生した際にはロールバックが発生しません。
そうなると、呼び出し元のコミットが発生してしまってトランザクションとコミットの組み合わせにずれが出てしまいます。

こんなの入れ子構造のtransactionにしたやつが悪いよと思うあなた。正解です。
しかし、やむを得なく実装が複雑になったり、最近はデコレーターでtransactionがはれてしまうので、一旦はってしまうみたいな運用をしてしまったりと事故が起こる可能性は大いにあります。
人は完璧なわけではないので、複雑になれば複雑になるほどこのような事故がおこりやすくなります。
特に上記のようなコミットでズレが起きてしまうと、コミットされてほしくないデータがコミットされたりと大事故につながる可能性があります。お金周りで発生なんてしたら目も当てられません。
その場合は、ロールバックしておいたほうがまだ安全でしょう。入れ子transactionでロールバックはモノによって挙動が違いますが、少なくともコミットされることはありません。

もちろんできるだけシンプルに、入れ子にしないようにするのが一番です。ですがそうはいかないのが現実です。
細かいところからできるだけ安全にコードが組めるように注意すると良いでしょう。