Pythonとトランザクション処理(SQLiteを学ぶ_25)

SQLiteを学んでいこうという連載の25回目です。前回の記事はこちらになります。

hirocom777.hatenadiary.org

前回は、Pythonから使用する場合のエラー処理の事例をご紹介しました。Pythonはプログラム言語なので、結果によって色々な処理を切り替えることができます。

今回はPythonから使用する場合のトランザクション処理です。

Pythonトランザクション処理

それではさっそくPythonでのトランザクション処理例を見ていきましょう。

まずはAnaconda PromptからSQLte3を起動して、データベースファイルを新規作成します。

sqlite> .open C:/Work/db_sample.db
sqlite> CREATE TABLE sample(id INTEGER UNIQUE,name TEXT,age INTEGER);
sqlite> INSERT INTO sample VALUES(1,"TANAKA",25);

前回同様id列にはUNIQUE制約が設定されています。次に、以下のコードを実行してみましょう。

import sqlite3

# データベースに接続
dbname = r'C:\Work\db_sample.db'
conn = sqlite3.connect(dbname)
cur = conn.cursor()

try:
    # トランザクションの開始
    conn.execute('BEGIN')

    # データベースの操作
    cur.execute('INSERT INTO sample VALUES(2,"YAMADA",30)')
    cur.execute('INSERT INTO sample VALUES(2,"OOTA",27)')

except sqlite3.IntegrityError:
    conn.rollback()
    print('DataBaseError')

except Exception as e:
    # 上記以外のエラー
    conn.rollback()
    print(f"Error: {e}")

else:
    # 操作を確定
    conn.commit()
    print('OK')

finally:
    # SQLで読み込んで表示
    for row in cur.execute('SELECT * FROM sample'):
        print(row)
    # データベース接続を閉じる
    cur.close()
    conn.close()

結果は以下のようになりました。

DataBaseError
(1, 'TANAKA', 25)

先のコードでは2つのレコードを書き込んでいますが、UNIQUE制約を設けているid列が重複しているのでエラーとなります。結果、トランザクション処理が働いてデータの登録はされないというわけです。

データ登録の部分を以下のように書き換えて、エラーを解消してみましょう。

    # データベースの操作
    cur.execute('INSERT INTO sample VALUES(2,"YAMADA",30)')
    cur.execute('INSERT INTO sample VALUES(3,"OOTA",27)')

結果は以下のようになって、正常にレコードが登録されました。

OK
(1, 'TANAKA', 25)
(2, 'YAMADA', 30)
(3, 'OOTA', 27)

その他のエラーが発生した場合

それではSQLiteではなくPython側でエラーが出た場合には、どうなるのでしょうか。データ登録の部分を以下のように書き換えてみましょう。

    # データベースの操作
    cur.execute('INSERT INTO sample VALUES(4,"MURAYAMA",22)')
    print(1 / 0)

登録するレコードのid列は重複していませんが、そのあとのprint関数では整数を0で割っていてるのでエラーとなってしまいます。結果は以下の様なりました。

Error: division by zero
(1, 'TANAKA', 25)
(2, 'YAMADA', 30)
(3, 'OOTA', 27)

『0で割っています』と表示されています。これは、以下の部分が働いた結果です。

except Exception as e:
    # 上記以外のエラー
    conn.rollback()
    print(f"Error: {e}")

このように記述すると、エラーが発生した場合にエラー内容にかかわらず処理を中断してエラー内容を返します。この処理を他のエラー処理の前に記述すると、その他のエラー処理が無効になってしまうので気を付けましょう。全体の流れとしては以下のようになります。

try:
    
    メインの処理

except:
    
    メインの処理でエラーが発生した場合の処理

except Exception as e:

    上記以外のエラーが発生した場合の処理

else:

    メインの処理が正常に実行された場合の処理

finally:

    メインの処理結果にかかわらず実行される処理

この流れでエラー処理はバッチリだと思います。

これでSQLiteの連載はいったん終了です

いかがでしょうか。SQLiteに関する連載はこれでいったん終了します。普段直接目にすることはないSQLiteデータベースですが、少しは理解が深まったと思います。また別なアプローチで学んでみたいと思います。お付き合いいただきありがとうございました!!

SQLite学習記事のまとめですはこちらから