【 MySQL の InnoDB によるトランザクション処理 】
概要 |
MySQL では、表作成時に無指定の場合テーブル形式は、MyISAM になります 既存表の形式は、SHOW TABLE STATUS で知る事ができます。また、 SHOW CREATE TABLE 表名によって表形式のオプション指定方法 を知る事もできます トランザクションを利用する場合は、テーブル形式は InnoDB を 使用します。以下にテーブル作成の CREATE 構文のサンプルを示し ます
|
CREATE TABLE 商品マスタ (
コード varchar(4),
商品名 varchar(50),
単価 int,
PRIMARY KEY(コード)
) TYPE=InnoDB
このテーブルを SHOW CREATE TABLE で表定義出力すると以下のようになります
CREATE TABLE `商品マスタ` (
`コード` varchar(4) NOT NULL default '',
`商品名` varchar(50) default NULL,
`単価` int(11) default NULL,
PRIMARY KEY (`コード`)
) TYPE=InnoDB
MyISAM 形式の既存表を InnoDB 形式に変更するには、以下の構文を使用します
ALTER TABLE 商品マスタ TYPE=InnoDB
以下は、InnoDB 関係のデフォルトのシステム変数の値です ( 4.0.16-nt )
|
変数名 |
値 |
1 |
innodb_additional_mem_pool_size |
1048576 |
2 |
innodb_buffer_pool_size
| 8388608 |
3 |
innodb_data_file_path
| ibdata1:10M:autoextend |
4 |
innodb_data_home_dir
| |
5 |
innodb_file_io_threads
| 4 |
6 |
innodb_force_recovery
| 0 |
7 |
innodb_thread_concurrency
| 8 |
8 |
innodb_flush_log_at_trx_commit
| 1 |
9 |
innodb_fast_shutdown
| ON |
10 |
innodb_flush_method
| |
11 |
innodb_lock_wait_timeout
| 50 |
12 |
innodb_log_arch_dir
| .\ |
13 |
innodb_log_archive
| OFF |
14 |
innodb_log_buffer_size
| 1048576 |
15 |
innodb_log_file_size
| 5242880 |
16 |
innodb_log_files_in_group
| 2 |
17 |
innodb_log_group_home_dir
| .\ |
18 |
innodb_mirrored_log_groups
| 1 |
19 |
innodb_max_dirty_pages_pct
| 90 |
概要 |
ある期間の複数のテーブルへの更新の整合性を保つ為のロック方法 であり、更新に対するキャンセル機能を持ったものです トランザクションは明示的にコマンドを発行する事によって作成され ます。MySQL では、START TRANSACTION か BEGIN または BEGIN WORK を使用します トランザクションの終了は、COMMIT または ROLLBACK を実行する か、セッションの終了時に暗黙的に行なわれます 更新をデータベースに反映するには、COMMIT を発行します。セッシ ョンの終了は ROLLBACK と同等ですが、必ず明示的に ROLLBACK を指定するのがプログラミングとして正しい使用法です 他からの更新は、先にロックされていた場合は innodb_lock_wait_timeout の値を最大値としてその時間待たされます。その時間内にロックしたセッ ションが COMMIT または ROLLBACK を実行するとロックは解除され ます 通常、SELECT 文はロックの影響を受けません、しかし、ロックされる 前の情報しか返す事はありません
|
以下に PHP における更新のサンプルを示します
require_once( "db.php" );
$SQL = new DB();
$SQL->Execute( "BEGIN" );
$Query = "UPDATE 商品マスタ SET 単価 = 1234 where コード = '0001'";
$ret = $SQL->Execute( $Query );
if ( !$ret ) {
$SQL->Execute( "ROLLBACK" );
}
else {
$SQL->Execute( "COMMIT" );
}
$SQL->Close();
AUTOCOMMIT |
AUTOCOMMIT は、セッションの変数でありデフォルトで 1 です。これ は、トランザクションの開始と終了の間以外は全て即更新されると言 う事です
|
以下の二つのソースコードは違った結果を表示します
require_once( "db.php" );
$SQL = new DB();
$SQL->Execute( "set autocommit = 1" );
$SQL->Execute( "BEGIN" );
$Query = "UPDATE 商品マスタ SET 単価 = 1234 where コード = '0001'";
$SQL->Execute( $Query );
$SQL->Execute( "COMMIT" );
$Query = "SELECT * FROM 商品マスタ where コード = '0001'";
$ret = $SQL->Query( $Query );
$column = $SQL->Fetch( $ret );
print_r($column);
# 自動コミットの為、以下の UPDATE 文は即実行される
# ROLLBACK する為には、明示的に BEGIN を実行する必要がある
$Query = "UPDATE 商品マスタ SET 単価 = 9999 where コード = '0001'";
$SQL->Execute( $Query );
$SQL->Execute( "ROLLBACK" );
$Query = "SELECT * FROM 商品マスタ where コード = '0001'";
$ret = $SQL->Query( $Query );
$column = $SQL->Fetch( $ret );
print_r($column);
$SQL->Close();
require_once( "db.php" );
$SQL = new DB();
$SQL->Execute( "set autocommit = 0" );
$SQL->Execute( "BEGIN" );
$Query = "UPDATE 商品マスタ SET 単価 = 1234 where コード = '0001'";
$SQL->Execute( $Query );
$SQL->Execute( "COMMIT" );
$Query = "SELECT * FROM 商品マスタ where コード = '0001'";
$ret = $SQL->Query( $Query );
$column = $SQL->Fetch( $ret );
print_r($column);
# 非自動コミットの為、前の COMMIT が新たなトランザクションの開始位置となる
$Query = "UPDATE 商品マスタ SET 単価 = 9999 where コード = '0001'";
$SQL->Execute( $Query );
$SQL->Execute( "ROLLBACK" );
$Query = "SELECT * FROM 商品マスタ where コード = '0001'";
$ret = $SQL->Query( $Query );
$column = $SQL->Fetch( $ret );
print_r($column);
$SQL->Close();
ガイドライン |
AUTOCOMMIT の値をどうするかは、システムで統一します。しかし、 本来のトランザクション処理は AUTOCOMMIT = 0 で行なうもので す。バッチ処理の場合は、AUTOCOMMIT = 1 でもかまいませんが、 通常そのような場合はある一定の更新件数毎に COMMIT を発行し ます ロックに対するタイムアウト時はエラーが返されます。そのような場合 は、ロールバックしてエラー表示を伴なう画面表示を行なうのが通常 です トランザクションはセッション内で整合性が保たれます。他の接続を 使用したり、一旦接続を解除するような事は避けなければなりません そういう意味でも、データベースへのアクセス関数等は意味を良く知 った上で使用しなければなりません ロックされている間に取得した SELECT 文での情報は古い情報であ る事に注意して下さい。テーブルの列に対する加算や減算に SELECT 文で得た情報を使用してはいけません。必ず UPDATE 文内で記述し て下さい 具体的なテストは、PHP の sleep 関数で行なう事ができます
|
エクスポートとインポート |
MySQL のバージョンアップは非常に多いので、最新のバージョンでの テストが必要になります。その際に要求されるのがデータベースのエク スポートとインポートです 最も簡単で解りやすいエクスポート方法は、以下のようになります mysqldump --all-database > ファイル名 インポートは以下の入力でログインしてから source ファイル名 を 実行します mysql -u root -p --default-character-set=sjis -s -s はサイレントモードです。結果の表示が抑制されます ※ MySQL の sjis 設定は、winmysqladmin.exe で行います
|
以下は、4.0.16 をアンインストールして 4.0.17 をインストールし、最初のサービス起動直後のログです ( C:\mysql\data\マシン名.err です )
InnoDB: The first specified data file .\ibdata1 did not exist:
InnoDB: a new database to be created!
031230 18:13:00 InnoDB: Setting file .\ibdata1 size to 10 MB
InnoDB: Database physically writes the file full: wait...
031230 18:13:02 InnoDB: Log file .\ib_logfile0 did not exist: new to be created
InnoDB: Setting log file .\ib_logfile0 size to 5 MB
InnoDB: Database physically writes the file full: wait...
031230 18:13:03 InnoDB: Log file .\ib_logfile1 did not exist: new to be created
InnoDB: Setting log file .\ib_logfile1 size to 5 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
031230 18:13:14 InnoDB: Started
以下は、mysql で、インポートした時のメッセージです ( MySQL と エラーメッセージの sjis 化処理は済ませてあります )
C:\mysql\bin>mysql -u root -p --default-character-set=sjis -s
Enter password:
mysql> source all.sql
ERROR 1050: Table 'columns_priv' は既にあります
ERROR 1050: Table 'db' は既にあります
ERROR 1062: '%-test%-' は key 1 において重複しています
ERROR 1050: Table 'func' は既にあります
ERROR 1050: Table 'host' は既にあります
ERROR 1050: Table 'tables_priv' は既にあります
ERROR 1050: Table 'user' は既にあります
ERROR 1062: 'localhost-root' は key 1 において重複しています
ERROR 1062: '%-root' は key 1 において重複しています
ERROR 1062: 'localhost-' は key 1 において重複しています
ERROR 1062: '%-' は key 1 において重複しています
|