最終更新日:
公開日:
レシピ
データベース SQLite
SQLite3のトランザクション
SQLite3でトランザクションを使用する方法について、実践的なコードを交えて解説します。
この記事のポイント
- SQLiteでトランザクションを実装する
- トランザクションのコミットとロールバックの役割を知る
- try〜catch文を使った実用的なコードを書く
目次
データベースの整合性を保持するためのトランザクション
今回は、データベースの整合性を保持するための仕組み「トランザクション」について解説します。
トランザクションを実装すると、データベースの処理中にエラーが起こってしまったとしても、データベースを処理前の状態に巻き戻すことができます。
実行が成功した時のみ、データベースに対する変更が「有効」となるため、予期せぬエラーに備える保険として活用することができるわけです。
これから解説を進めるにあたり、次のようなテーブルがあることを前提とします。
カラム名 | 型 | その他 |
---|---|---|
id | INTEGER | PRIMARY KEY |
name | TEXT | NOT NULL |
age | INTEGER | NOT NULL |
created_datetime | TIMESTAMP | DEFAULT (datetime(CURRENT_TIMESTAMP,’localtime’)) |
トランザクションについてより詳しくは、「mysqliのトランザクション」の「データの整合性を保つためのトランザクション」セクションをご覧ください。
こちらはMySQLの記事ですが、データベースのトランザクションに対する考え方は共通しています。
トランザクションを試してみる
まずは単純にデータを登録するための、次のようなコードを用意します。
コード例
<?php
// 変数の初期化
$db = null;
$sql = null;
$res = null;
// データベースへ接続
$db = new SQLite3("./sqlite/test.sqlite3");
// データの追加
$sql = 'INSERT INTO test(
name, age, created_datetime
) VALUES (
"飯田", 22, "2017-07-25 17:00:00"
)';
$res = $db->query($sql);
実行すると、普通にtestテーブルへデータが1つ追加されます。
データベースの出力例
...
9 | 石田 | 23 | 2017-07-08 22:00:00
10 | 西川 | 31 | 2017-07-07 11:00:00
11 | 鹿島 | 30 | 2017-07-25 16:20:00
12 | 飯田 | 22 | 2017-07-25 17:00:00
続いて、トランザクションに関するコードを追加してみましょう。
赤い箇所が追加したコードです。
コード例
... 途中省略 ...
// トランザクション開始
$db->exec('begin');
// データの追加
$sql = 'INSERT INTO test(
name, age, created_datetime
) VALUES (
"高橋", 24, "2017-07-28 12:00:00"
)';
$res = $db->query($sql);
// ロールバック
$db->exec('rollback');
コードを実行してみると、今度はデータが追加されません。
処理の成功・失敗に関わらず、強制的に「ロールバック」を行っているためです。
ロールバックを行うと、トランザクションを開始する「$db->exec(‘begin’);」から「$db->exec(‘rollback’);」の間にある全ての処理がキャンセルされます。
キャンセルではなく実行結果をしっかりデータベースへ反映したい場合は、「コミット」する必要があります。
この処理は、「$db->exec(‘commit’);」と書くことで実行できます。
試しに、先ほどロールバックしていた部分をコミットに変更してみましょう。
コード例
... 途中省略 ...
// トランザクション開始
$db->exec('begin');
// データの追加
$sql = 'INSERT INTO test(
name, age, created_datetime
) VALUES (
"高橋", 24, "2017-07-28 12:00:00"
)';
$res = $db->query($sql);
// コミット
$db->exec('commit');
もう一度コードを実行してみると、今度はデータがしっかり追加されていることが確認できます。
データベースの出力例
...
9 | 石田 | 23 | 2017-07-08 22:00:00
10 | 西川 | 31 | 2017-07-07 11:00:00
11 | 鹿島 | 30 | 2017-07-25 16:20:00
12 | 飯田 | 22 | 2017-07-25 17:00:00
13 | 高橋 | 24 | 2017-07-28 12:00:00
ロールバックとコミットについて、基本的な動作を確認することができました。
続いて、実用的な使い方をみていきましょう。
try〜catch文で囲む
トランザクションは、正常に処理が完了したときのみ「コミット」し、処理が途中でエラーとなった場合は「ロールバック」するという分岐の判断が必要です。
この「エラーが起こったかどうか」を判断するための分岐処理として、PHPでは一般的に「try〜catch文」を使います。
基本的なtry〜catch文の使い方
try {
...実行したい処理...
// コミット
$db->exec('commit');
} catch(Exception $e) {
// ロールバック
$db->exec('rollback');
$error = $e->getTraceAsString();
}
通常はtry文の中の処理のみ実行され、catch文の処理は無視されます。
しかし、途中でエラーが発生した場合はcatch文へ移り、ロールバックをはじめとした処理を実行します。
先ほどまで使っていたコードをtry文に入れると、次のようなコードとなります。
index.php
<?php
// 変数の初期化
$db = null;
$sql = null;
$res = null;
// データベースへ接続
$db = new SQLite3("./sqlite/test.sqlite3");
// トランザクション開始
$db->exec('begin');
try {
// データの追加
$sql = 'INSERT INTO test(
name, age, created_datetime
) VALUES (
"島田", 28, "2017-08-01 10:00:00"
)';
$res = $db->query($sql);
// コミット
$db->exec('commit');
} catch(Exception $e) {
// ロールバック
$db->exec('rollback');
// エラーメッセージの取得
$error = $e->getTraceAsString();
return;
}
正常に処理が完了するとデータベースに「島田さん」のデータが追加され、もし途中で何かしらのエラーが行った場合はロールバック(取り消し)して処理を終了します。
データベースの出力例
...
9 | 石田 | 23 | 2017-07-08 22:00:00
10 | 西川 | 31 | 2017-07-07 11:00:00
11 | 鹿島 | 30 | 2017-07-25 16:20:00
12 | 飯田 | 22 | 2017-07-25 17:00:00
13 | 高橋 | 24 | 2017-07-28 12:00:00
14 | 島田 | 28 | 2017-08-01 10:00:00
以上、SQLite3におけるトランザクションについてでした。
今回はINSERT INTO文に対してトランザクションを使用しましたが、UPDATE文やDELETE文など他の処理も同じ方法で実装することが可能です。