MySQLと画像ファイルのトランザクション問題を考える

presented by 役に立つかもしれないBlog

画像データを外部ファイルで持つのと、データベースに格納しておくのとでは、どちらが良いのでしょうか? なかなか難しい問題です。

今回は画像ファイルを外部に持つことのメリット・デメリットを考え、落とし所を探っていくことにしましょう。

メリットとデメリット

メリット

デメリット

特に、トランザクションの問題は深刻です。 データベース上のデータと、画像ファイルの関係性が崩れてしまう可能性があるためです。

画像削除にもトランザクションを実現してみる

この問題を回避する方法をいろいろ考えた結果、以下のステップでトランザクションぽいことが出来るのではないかと思いつきました。

データベース・トランザクションと画像ファイル削除のステップ

Linux上で/tmp ディレクトリの内容は定期的にクリアされるので、6のステップで失敗してもいずれ削除されることになります。

これをPHPで実現したのが以下のコードです。

やや実用的にするために、ユーザーごとの画像フォルダを削除するという想定で書いてみました。 基本的な命令しか使っていないのでPHP4, PHP5両方で動作すると思います。

稚拙なコードですが、参考にしてみてください。

サンプルコード

/**
 * ディレクトリの削除関数
 * ファイルが中にあった場合もすべて削除します。
 * 削除対象のディレクトリの中はすべてファイルでなければなりません。
 *
 * @param string $dir 削除対象のディレクトリ
 * @return boolean 成功した場合trueを返します
 */
function removeDir($dir) {
	if (is_dir($dir) && !is_link($dir)) {
		foreach(glob($dir.'/*') as $sf) {
			if (!removeDir($sf) ) return false;
		}
		return rmdir($dir);
	} else {
		return unlink($dir);
	}
}

/**
 * 画像フォルダなどの個別データディレクトリがある場合は
 * 一旦/tmp ディレクトリにリネームして移動させ、成功したら削除します。
 * 失敗したら退避先のディレクトリから元に戻します。
 */
 
/**
 * MySQLへの接続
 */
if (!($cn = mysql_connect("localhost", "myUser", "myPassword"))) return false;
if (!(mysql_select_db("myDB"))) return false;

/**
 * 削除したいディレクトリ
 */
$dataDir = "/path/to/mydataDir_001";

/**
 * 一時退避時のディレクトリ
 */
$tmpDataDir = "/tmp/mydataDir_001";

if (is_dir($dataDir) and !rename($dataDir, $tmpDataDir)) return false;

mysql_query("BEGIN");

if (mysql_query("DELETE FROM mytable WHERE myid = '001'") == false) {
	/**
	 * 失敗 (フォルダを戻してロールバック)
	 */
	if (is_dir($tmpDataDir)) rename($tmpDataDir, $dataDir);
	mysql_query("ROLLBACK");
	return false;
} else {
	/**
	 * 成功 (フォルダを削除してコミット)
	 */
	if (is_dir($tmpDataDir)) removeDir($tmpDataDir);
	mysql_query("COMMIT");
	return true;
}
    このエントリーをはてなブックマークに追加

このページに関連のある記事はこちら

コメントフォーム