エントリー

カテゴリー「データベース」の検索結果は以下のとおりです。

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/

SQLite3でオートインクリメント

細かい部分でつまづきつつ、PHP Labo のプログラムを書き換え中。

SQLite2でオートインクリメントな列を作りたい場合、テーブル作成時に

no INTEGER UNSIGNED NOT NULL PRIMARY KEY

としていたのだけど、SQLite3ではデータの挿入ができませんでした…。

address.no may not be NULL

とか言われてしまいます。(address はテーブル名。)色々試したところ、

no INTEGER PRIMARY KEY

ならSQLite2でもSQLite3でも大丈夫だった。調べてみると、NOT NULL を指定しているとバージョンによって微妙に挙動が異なるらしい。うーむ。

ちなみにSQLite3からは AUTOINCREMENT というキーワードが追加されているらしいけど、SQLite2では動作しないので上の方法で行くとします。

イラスト系サイト用コンテンツ管理システム構想中

「MySQL、SQLite、ファイルに対応」の実装方法を考えているのですが、なかなか進まない…。

「同じ命令でデータを扱えるように、専用の命令を作成」ができればいいけど「プラグインで独自にデータを保持できるように」まで考えると、なかなか自分の頭ではまとめきれない…。
命令の仕様が複雑になっても嫌だし…。

だからといって、「単純にプログラム内で条件分岐する」でも、それはそれでプラグインを作るときの労力が大きいし…。

ひとまずデータベースは置いといて、ファイルのみに対応させるかなぁ…。その後、可能ならデータベースへの対応を考えるか、難しければデータベース対応版を別に作るか。

イラスト系サイト用コンテンツ管理システム

Web Diary Professional Ver4 の次期バージョンにあたるツールのメモ。
素直に Ver5 とはせずに、名前も変えて作る可能性が高いです。(開発言語もPHPに変えるし。)
また、Ver4 の配布は終了せずに、平行して開発するつもり。

以下、ツールのメモ。実現可能かどうかは考慮せずに「できたらいいな」を書いているだけ。完成日は不明。完成する日が来るかどうかも不明。(ぉ
思いついたら追記していきます。

基本方針

  • 主にイラスト系サイトで利用されることを想定した、高機能なコンテンツ管理システム
  • 初期状態では「ただの日記ツール」くらいにシンプルなインターフェースにしたい
  • 仕事でプログラムを作るとき、ベースとして使えるものにしたい
  • 個人的に使いたいツールは「テキスト主体のブログツール」「時々イラストを描きたい」「時系列でないページも作りたい」

プログラムを作る本人は、あまり絵を描けないというのが悲しい…。でも、管理するための仕組みを作るのは大好きなのです。

機能メモ

  • 「ビジュアルコンテンツ主体のサイトをうまく構成してくれるWebのツール」「イラストサイト専門のブログ(みたいなもの)というシステム」ができればいいなぁ
  • パーソナルSNSとして使えるようにしたい
    「全体に公開&コメントも全体から受付」(普通のブログ)
    「全体に公開&コメントは許可したユーザーから受付」
    「一部のコンテンツを、許可したユーザーにのみ公開&コメント受付」
    「許可したユーザーにのみ公開&コメント受付」
    「許可したユーザーにのみ公開&コメントも受け付けない」
    などから選択して運営できる
    さらに、ユーザーごとに「どこまで公開するか?」を設定できると良いかも
  • 「アクセスはトップページから」に強制できる
    サイトを1つの作品として完結できる仕組み
    もちろん利用するかどうかは管理者次第
  • ファイルへの直リンクも制限できるようにしたい
  • WinXPのフォルダ機能のように、文章・画像・音楽などで見せ方を変えられるといいかも
  • 小説の管理としても利用できるようにしたい
  • 標準でタギングとカテゴリの両方に対応させる(もしくは、どちらかをプラグインにする)
    カテゴリは、無制限の階層化と、複数カテゴリに対応させたい
  • お絵かきアプレット対応
  • アクセス解析、アクセスカウンタ、拍手などはプラグインとして実装する

技術メモ

  • PHP4とPHP5に対応(PHP5に限定しても大丈夫かも)
  • メイン処理は非オブジェクト指向、既存フレームワークも使わない
    PHPを少し勉強すれば、できればプログラム初心者でも、すんなり読めるコードが理想
    プログラム初心者がコードを編集しても、セキュリティ問題が発生しにくい構造にしたい
  • MySQL、SQLite、ファイルに対応
    同じ命令でデータを扱えるように、専用の関数かクラスかフレームワークもどきを自作(でも、独自ルールの理解を強要することになるのはデメリットかも…)
    もしくは単純に、プログラム内で条件分岐する(でも、プログラムの可読性が下がるかも…)
  • デフォルトではファイルを使用、設置はできる限り簡単に(最低でも Web Diary Pro と同等に)
    「プログラムを入手 → 全部アップロード → プログラムにアクセス → 管理者パスワードを設定すれば設置完了」ぐらいにしたい
  • データベース接続はPEAR::DB(PDOを使っても大丈夫かも)
  • 管理画面などのインターフェースも、デフォルトではできる限りシンプルに
    でも、操作に慣れた人はドンドン拡張&高機能化できるようにしたい
  • テンプレートエンジンはSmarty
  • プラグインの仕様は、基本的に PHP Labo のプログラムと同じ(加えて、入力項目の追加に対応したい)
  • 動的出力(HTML書き出しに対応するかは考え中。)
  • Web Diary Pro Ver4 に実装されている機能には、ひととおり対応する(HTML書き出しに対応するかは考え中。)
  • Web Diary Pro、Web Gallery Pro などにもらった要望にも、ひととおり対応したい
  • コア部分は比較的シンプルにして、プラグインで機能を拡張する(ただし、デフォルトである程度プラグインを導入済みにしておく)

参考ページ

ツール名

  • アルファベット4~6文字くらいの名前にしたい
  • 「Web Diary」とか「PHP Blog」のようなヒネリの無い名前ではなく、独自の名前にしたい
  • ツールの基本方針が伝わるような英単語、もしくは造語にしたい
  • 実は、ツール名が一番の悩みの種だったり

データベースとファイル

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