PHPプログラミング

最終更新日:
公開日:

レシピ

データベース SQLite

SQLite3のトランザクション

SQLite3でトランザクションを使用する方法について、実践的なコードを交えて解説します。

この記事のポイント

  • SQLiteでトランザクションを実装する
  • トランザクションのコミットとロールバックの役割を知る
  • try〜catch文を使った実用的なコードを書く

目次

データベースの整合性を保持するためのトランザクション

今回は、データベースの整合性を保持するための仕組み「トランザクション」について解説します。

トランザクションを実装すると、データベースの処理中にエラーが起こってしまったとしても、データベースを処理前の状態に巻き戻すことができます。
実行が成功した時のみ、データベースに対する変更が「有効」となるため、予期せぬエラーに備える保険として活用することができるわけです。

これから解説を進めるにあたり、次のようなテーブルがあることを前提とします。

テーブル名:test
カラム名その他
idINTEGERPRIMARY KEY
nameTEXTNOT NULL
ageINTEGERNOT NULL
created_datetimeTIMESTAMPDEFAULT (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文など他の処理も同じ方法で実装することが可能です。