エントリー

タグ「MySQL」の検索結果は以下のとおりです。

Webアプリケーションへの同時アクセス対策メモ

Webアプリケーションへの同時アクセス対策メモ

XAMPPの Apache Bench で同時アクセスを再現するメモ。テストした環境はWindows7。Apache Bench の使い方は以下を参考に。

XAMPPをCドライブ直下にインストールした場合、以下の手順で Apache Bench を使える。

> cd C:\xampp\apache\bin
> ab -n 15 -c 15 http://localhost/~test/ab/

「-n 15 -c 15」で「15人が同時にアクセスする(合計15回アクセス)」状況がテストできる。(「-n 15 -c 1」なら「1人が合計15回アクセスする」状況になるので、同時アクセスにはならない。)

以下で同時アクセスのテストとその対策を行う。

ファイルを使った例

<?php

/*
 * No.2をカウントアップ(最大値100)
 */

if ($fp = fopen('logs/count.log', 'r+')) {
  $data = '';
  while ($line = fgets($fp)) {
    list($id, $count) = explode("\t", rtrim($line));

    if ($id == 2) {
      if ($count < 100) {
        $data .= "$id\t" . ++$count . "\n";
      } else {
        exit('Limit');
      }
    } else {
      $data .= $line;
    }
  }

  rewind($fp);
  fwrite($fp, $data);
  ftruncate($fp, ftell($fp));

  fclose($fp);
} else {
  exit('Error');
}

exit('Complete');

logs/count.log の内容は以下のとおり。

1	10
2	20
3	30
4	40
5	50

これで上のPHPプログラムにアクセスすると、2の行が1カウントアップされる。何度もリロードすると、その回数だけカウントアップされる。

> ab -n 30 -c 30 http://localhost/~test/ab/count.php

30人の同時アクセスを発生させてみると、正しくカウントできないのが確認できる。

<?php

/*
 * No.2をカウントアップ(最大値100)
 */

if ($fp = fopen('logs/count.log', 'r+')) {
  flock($fp, LOCK_EX);  //ファイルロック

  $data = '';
  while ($line = fgets($fp)) {
    list($id, $count) = explode("\t", rtrim($line));

    if ($id == 2) {
      if ($count < 100) {
        $data .= "$id\t" . ++$count . "\n";
      } else {
        exit('Limit');
      }
    } else {
      $data .= $line;
    }
  }

  rewind($fp);
  fwrite($fp, $data);
  ftruncate($fp, ftell($fp));

  fclose($fp);
} else {
  exit('Error');
}

exit('Complete');

ファイルロックを行えば、正しくカウントされるようになる。

データベースを使った例

<?php

/*
 * No.2をカウントアップ(最大値100)
 */

try {
  $pdo = new PDO('mysql:dbname=test;host=localhost', 'root', '1234', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
  $pdo->query('SET NAMES utf8');

  $stmt = $pdo->prepare('SELECT count FROM count_test WHERE id = :id');
  $stmt->bindValue(':id', 2, PDO::PARAM_INT);
  $stmt->execute();

  $data = $stmt->fetch(PDO::FETCH_ASSOC);

  if ($data['count'] < 100) {
    $stmt = $pdo->prepare('UPDATE count_test SET count = count + 1 WHERE id = :id');
    $stmt->bindValue(':id', 2, PDO::PARAM_INT);
    $stmt->execute();
  }
} catch (PDOException $e) {
  exit($e->getMessage());
}

exit('Complete');

count_test の定義は以下のとおり。

CREATE TABLE count_test(
  id    INT UNSIGNED NOT NULL,
  count INT UNSIGNED,
  PRIMARY KEY(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

これで上のPHPプログラムにアクセスすると、2の行が1カウントアップされる。何度もリロードすると、その回数だけカウントアップされる。

ab -n 200 -c 200 http://localhost/~test/ab/count.php

200人の同時アクセスを発生させてみると、正しくカウントできないのが確認できる。

<?php

/*
 * No.2をカウントアップ(最大値100)
 */

try {
  $pdo = new PDO('mysql:dbname=test;host=localhost', 'root', '1234', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
  $pdo->query('SET NAMES utf8');

  $pdo->beginTransaction();  //トランザクション開始

  $stmt = $pdo->prepare('SELECT count FROM count_test WHERE id = :id FOR UPDATE');  //行ロック
  $stmt->bindValue(':id', 2, PDO::PARAM_INT);
  $stmt->execute();

  $data = $stmt->fetch(PDO::FETCH_ASSOC);

  if ($data['count'] < 100) {
    $stmt = $pdo->prepare('UPDATE count_test SET count = count + 1 WHERE id = :id');
    $stmt->bindValue(':id', 2, PDO::PARAM_INT);
    $stmt->execute();
  }

  $pdo->commit();  //コミット
} catch (PDOException $e) {
  $pdo->rollBack();  //ロールバック

  exit($e->getMessage());
}

exit('Complete');

トランザクションと行ロックを行えば、正しくカウントされるようになる。

MySQLのテーブル仕様変更メモ

個人的にはテーブルの仕様変更コマンドはほとんど使わないのですが、たまにどうしても必要になることがあります。
そして先日、既存のテーブルに手を加える必要が出ました…。これまでその都度調べていたけど、自分が使いそうなものだけメモしておきます。

#「番号」「氏名」「電話番号」を格納できるテーブルを作成
CREATE TABLE address(
  no   INT         NOT NULL,
  name VARCHAR(80) NOT NULL,
  tel  VARCHAR(80) NOT NULL
);

#「読み仮名」を格納する列を追加
ALTER TABLE address ADD kana VARCHAR(80) NOT NULL; #末尾に追加
ALTER TABLE address ADD kana VARCHAR(80) NOT NULL FIRST; #先頭に追加
ALTER TABLE address ADD kana VARCHAR(80) NOT NULL AFTER name; #「名前」の直後に追加

#「年齢」を格納する列を追加
ALTER TABLE address ADD age INT NOT NULL; #末尾に追加
ALTER TABLE address ADD age INT NOT NULL FIRST; #先頭に追加
ALTER TABLE address ADD age INT NOT NULL AFTER name; #「名前」の直後に追加

#「読み仮名」を格納する列を削除
ALTER TABLE address DROP kana;

#「年齢」を格納する列をVARCHAR型に変更
ALTER TABLE address CHANGE age age VARCHAR(80) NOT NULL;

#「年齢」を格納する列の名前を変更
ALTER TABLE address CHANGE age toshi INT NOT NULL;

もちろん、データベース管理ツールを使うのも有効です。

MySQL&SQLite用のデータベース管理ツール(改良版)

以前に作成したデータベース管理ツールを改良しました。

PHP Labo のプログラムをPHP5用に書き換えるにあたり、簡易な管理ツールが欲しくなったので作成。以前作成したものを使えば大丈夫…と思いきや、PDOを使わないとSQLite3には接続できないので…。

そんな訳で、実行にはPHP5+PDOが必要です。また、以前は断念したデータのインポート機能も実装。なかなか便利。

詳細とダウンロードは以下のページから行えます。

http://www.php-labo.net/download/tool/admin/

データベースとファイル

PHPでデータベース対応のプログラムをいくつか作ってきましたが、データベースとファイルの両方に対応したプログラムを作成しようと考え中。PHP Labo のプログラムとは別に、1つ徹底的に高機能なプログラムを作りたいのです。

その際、データを扱う処理をどんなふうに書くか悩み中。

同じ命令でMySQLもSQLiteもファイルも扱えるような、有名どころのクラスがあればいいけど、どうも無いっぽい。うーん、プログラム内で単純に条件分岐して各処理を併記するかなぁ…。可読性が下がりそうで少し嫌だけど。

MySQL&SQLite用のデータベース管理ツール

この記事の続き。数日前から自作のデータベース管理ツールを使っています。基本的には phpminiadmin 以上 SQLiteManager 未満くらいの機能ですが、なかなか便利に使えています。(自分用に作ったから当然か。) スクリーンショットはこんな感じ。↓

20080322.png

phpMyAdmin や SQLiteManager を使い慣れている方には役不足なツールですが、「データを少し編集したい」という場合には便利かもしれません。一応さらしておきますので、よければどうぞ。

DB Admin ダウンロード

以下、簡単に特徴を記載しておきます。

  • MySQLとSQLiteに対応したデータベース管理ツール
  • SQLの文法がある程度解る人向け
  • 基本的にはphpminiadminのようなインターフェイス
  • データの一覧表示やテーブルの削除など、よく利用するコマンドはSQLを入力しなくても実行可能
  • データの登録&編集はフォームから可能
  • SQLite利用時、VACUUMを実行可能
  • データのエクスポートとインポートが可能
  • プログラムファイルは1つで、サイズは約40KB
  • 実行にはPHP5+PDOが必要

ライセンスはGPL。サポート無しですが、不具合はこっそり教えてくれると嬉しいです。「このツールを使ったらデータが全部消えた」とか言われても責任は持てませんので、使用する前にバックアップはとっておきましょう。(^^;

データベース管理ツール作成中

データベースの管理ツールとしては phpMyAdminSQLiteManager が有名だと思うけど、もっと簡易なツールを作成中。
データを少し編集したいとき、これらのツールをアップロードするのは面倒です。でも、SQLを送りつけるミニプログラムを毎回自作するのも十分に面倒なのです。

phpminiadmin は結構いい感じなのですが、データの編集時にSQLを直接入力するのは面倒すぎます…。

…という訳で、

  • MySQLとSQLiteに対応したデータベース管理ツール
  • 基本的にはphpminiadminのようなインターフェイス
  • データの登録&編集はフォームから可能
  • その他、(自分が)よく使う機能はSQLを直接入力しなくても操作できるように
  • プログラムファイルは1つで、サイズは数十KBに収まるくらい

というツールを作成中。現在、半分くらいは作れた。
でも、データ編集機能の実装が非常に面倒なので、ちょっと嫌になりそう…。

データベース

データベースはMySQLを使用するつもりだったのですが、ロリポップでは色々と問題があるのですね…。(このサイトはロリポップで運営中。)

以前から気になっていたけど、MySQLに接続するだけで結構時間がかかります…。さらに今回気付いたけど、MySQLのバージョンが4.0なのでUTF-8が利用できず、EUC-JPで固定らしい。これは痛い。

調べたら色々出てきたけど、さくらも同じらしい。

どうするか迷ったけど、ロリポップはSQLiteもインストールされているのでSQLiteに変更。非常に高速な上に、文字コードの問題も解決できました。

SQLiteはPHP5から標準で実装されていることだし、今後はSQLiteで進めていくとします。

ページ移動

  • 前のページ
  • 次のページ
  • ページ
  • 1

ユーティリティ

カテゴリー

検索

エントリー検索フォーム
キーワード

過去ログ

過去ログ表示フォーム
キーワード

Feed