Python SQLite トランザクション処理のベストプラクティス
Python で SQLite を用いたトランザクション処理
データベース操作において、データの整合性を保つために重要な概念が トランザクション です。トランザクションは、複数のデータベース操作をひとまとまりとして扱い、原子性(indivisibility)、一貫性(consistency)、分離性(isolation)、耐久性(durability)という4つの特性を満たすように処理します。
Python と SQLite でのトランザクション
Python では、sqlite3
モジュールを用いて SQLite データベースにアクセスできます。sqlite3
モジュールは、トランザクション処理を含むデータベース操作に必要な機能を提供しています。
トランザクションの基本操作
以下の3つの操作で、トランザクションの基本的な処理を実行できます。
- 開始:
begin()
メソッドを呼び出すことで、トランザクションを開始します。 - 操作: トランザクション内で、INSERT、UPDATE、DELETE などのデータベース操作を実行します。
ロールバック
もし、トランザクション内でエラーが発生した場合、rollback()
メソッドを呼び出すことで、トランザクション内の操作をすべて取り消すことができます。
コード例
import sqlite3
# データベース接続
conn = sqlite3.connect('example.db')
# カーソル取得
cursor = conn.cursor()
try:
# 残高更新処理開始
cursor.execute('BEGIN')
# 引出口座から出金
cursor.execute('UPDATE accounts SET balance = balance - 100 WHERE id = 1')
# 預入口座へ入金
cursor.execute('UPDATE accounts SET balance = balance + 100 WHERE id = 2')
# 残高更新処理確定
cursor.execute('COMMIT')
except Exception as e:
# エラー発生時ロールバック
cursor.execute('ROLLBACK')
print('エラーが発生しました:', e)
# データベース切断
conn.close()
補足事項
- SQLite はデフォルトでオートコミットモードが有効であり、各 SQL 文が独立したトランザクションとして即座にコミットされます。明示的にトランザクションを使用する場合は、
autocommit
モードを無効にする必要があります。 - トランザクションのロックレベルは、
isolation_level
属性を設定することで変更できます。ロックレベルによって、同時実行されるトランザクション間のデータの可視性が制御されます。
Python SQLite トランザクション処理サンプルコード
import sqlite3
# データベースファイル名
db_file = 'example.db'
def create_table():
"""
データベースとテーブルを作成する関数
"""
# データベース接続
conn = sqlite3.connect(db_file)
cursor = conn.cursor()
# テーブル作成クエリ
table_create_query = """
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
balance INTEGER NOT NULL
);
"""
# テーブル作成実行
cursor.execute(table_create_query)
# データベース切断
conn.close()
def transfer_funds(from_id, to_id, amount):
"""
口座間送金を行う関数
"""
# データベース接続
conn = sqlite3.connect(db_file)
cursor = conn.cursor()
try:
# トランザクション開始
cursor.execute('BEGIN')
# 送金元口座の残高更新
cursor.execute('UPDATE accounts SET balance = balance - ? WHERE id = ?', (amount, from_id))
# 送金先口座の残高更新
cursor.execute('UPDATE accounts SET balance = balance + ? WHERE id = ?', (amount, to_id))
# トランザクションコミット
cursor.execute('COMMIT')
print(f"{amount} 円を {from_id} から {to_id} へ送金しました。")
except Exception as e:
# エラー発生時ロールバック
cursor.execute('ROLLBACK')
print('送金処理中にエラーが発生しました:', e)
# データベース切断
conn.close()
# テーブル作成
create_table()
# 口座情報
accounts = [
{'name': 'Alice', 'balance': 1000},
{'name': 'Bob', 'balance': 500},
]
# 初期残高登録
conn = sqlite3.connect(db_file)
cursor = conn.cursor()
for account in accounts:
cursor.execute('INSERT INTO accounts (name, balance) VALUES (?, ?)', (account['name'], account['balance']))
conn.commit()
conn.close()
# 送金処理実行
transfer_funds(1, 2, 100)
transfer_funds(2, 1, 50) # 残高不足によりエラー発生
# 残高確認
conn = sqlite3.connect(db_file)
cursor = conn.cursor()
cursor.execute('SELECT * FROM accounts')
for account in cursor.fetchall():
print(f"{account['id']}: {account['name']} - 残高: {account['balance']}")
conn.close()
説明
create_table()
関数は、データベースとテーブルを作成します。transfer_funds()
関数は、口座間送金を行います。この関数は、トランザクションを使用して送金処理の原子性を保証します。- メイン部分では、口座情報を作成し、初期残高を登録します。その後、
transfer_funds()
関数を使用して送金処理を実行し、残高を確認します。
ポイント
- トランザクションは、
BEGIN
とCOMMIT
で囲むことで開始と終了を明示的に指定します。 - エラーが発生した場合、
ROLLBACK
を使用してトランザクションをロールバックします。 - 送金処理のような複数の操作をひとまとめにして実行する必要がある場合、トランザクションを使用することでデータの整合性を保つことができます。
このサンプルコードを参考に、具体的なアプリケーションに合わせてトランザクション処理を組み込んでみてください。
Python SQLite トランザクション処理の代替方法
Python では、with
ステートメントを用いたコンテキストマネージャーを利用して、トランザクション処理を簡潔に記述することができます。
import sqlite3
def transfer_funds_with_context_manager(from_id, to_id, amount):
"""
コンテキストマネージャーを用いた送金処理
"""
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
try:
with conn.cursor() as cursor:
# トランザクション開始
cursor.execute('BEGIN')
# 送金元口座の残高更新
cursor.execute('UPDATE accounts SET balance = balance - ? WHERE id = ?', (amount, from_id))
# 送金先口座の残高更新
cursor.execute('UPDATE accounts SET balance = balance + ? WHERE id = ?', (amount, to_id))
# トランザクションコミット
except Exception as e:
# エラー発生時ロールバック
conn.rollback()
print('送金処理中にエラーが発生しました:', e)
# コミット/ロールバックは自動的に処理される
# 送金処理実行
transfer_funds_with_context_manager(1, 2, 100)
transfer_funds_with_context_manager(2, 1, 50) # 残高不足によりエラー発生
with
ステートメントを用いて、コネクションオブジェクトとカーソルオブジェクトを自動的に管理します。conn.cursor()
で取得したカーソルオブジェクトをwith
ステートメント内で使用すると、COMMIT
またはROLLBACK
が自動的に呼び出されます。- トランザクション処理の記述が簡潔になり、コードの可読性が向上します。
- ライブラリ: SQLAlchemy などのライブラリを使用することで、より高度なトランザクション処理やオブジェクト指向的なコード記述を実現できます。
- ロック: 同時実行されるトランザクション間の衝突を避けるために、ロック機構を用いる方法もあります。
選択のポイント
- コードの簡潔性: コンテキストマネージャーは、シンプルなトランザクション処理に適しています。
- 機能性: 複雑なトランザクション処理やオブジェクト指向的なコード記述には、ライブラリが適しています。
- パフォーマンス: ロック機構を用いる場合は、パフォーマンスへの影響を考慮する必要があります。
上記に加え、以下の点が重要です。
- 使用するデータベースシステムやアプリケーションの要件に応じて、適切な方法を選択してください。
- トランザクション処理に関するベストプラクティスを理解し、適切なロックレベルや分離レベルを設定するようにしましょう。
- エラー処理やデッドロック対策を適切に行うことで、トランザクション処理の信頼性を高めることができます。
python-2.7 sqlite python-db-api