今表示されているデータはテンプレートに直接書いているダミーです。
これをデータベースから取得して表示します。
今回のソース
データベースからデータを取るためには、
データベースをインストールし、データを入れておかなければなりません。
以前と同様、環境構築もかんたんに記載します。
Firebirdインストール
データベースはFirebirdを使います。Firebirdに必要なものをインストール
# yum -y install libstdc++-4.4.4-13.el6.i686 # yum -y install ncurses-libs-5.7-3.20090208.el6.i686
Firebird公式からSuperserverをダウンロードしてインストール
# wget http://sourceforge.net/projects/firebird/files/firebird-linux-amd64/2.5.1-Release/FirebirdSS-2.5.1.26351-0.amd64.rpm/download # rpm -ivh FirebirdSS-2.5.1.26351-0.amd64.rpm
アプリ用データベース準備
Webアプリ用のユーザーを作成
# /opt/firebird/bin/gsec -user sysdba -pass XXXXXX -add bbs -pw bbs
データベースファイル置き場を作成
# mkdir /usr/local/bbs/database # chown firebird:firebird /usr/local/bbs/database
isqlを起動
# /opt/firebird/bin/isql
データベースを作成します
> create database '/usr/local/bbs/database/bbs.fdb' user 'bbs' password 'bbs';
データベースに接続
> connect '/usr/local/bbs/database/bbs.fdb' user 'bbs' password 'bbs';
テーブル定義を流し込みます。
CREATE SEQUENCE thread_sequence; CREATE TABLE threads ( id INTEGER NOT NULL PRIMARY KEY, title VARCHAR(1024) NOT NULL, registered TIMESTAMP NOT NULL ); CREATE SEQUENCE response_sequence; CREATE TABLE responses ( id INTEGER NOT NULL PRIMARY KEY, thread_id INTEGER NOT NULL, name VARCHAR(256) NOT NULL, content VARCHAR(10240) NOT NULL, registered TIMESTAMP NOT NULL );
データ取得用に適当なデータも入れておきます。
INSERT INTO threads(id, title, registered) VALUES (next value for thread_sequence, 'homu', CURRENT_TIMESTAMP); INSERT INTO responses(id, thread_id, name, content, registered) VALUES (next value for response_sequence, 1, 'homuhomu', 'homuhomuhomu', CURRENT_TIMESTAMP);
アプリからデータを取得
SQLの実行は次の手順で行います。- データベースへ接続
- 以下必要回数繰し
- トランザクションを開始
- 以下必要回数繰し
- SQL実行準備(メモリ確保等)
- 以下必要回数繰し
- SQLに変数をセット(必要であれば)
- SQL実行
- SQLの戻り値を取得(必要であれば)
- 以下必要回数繰し
- SQL終了処理(メモリ解放等)
- トランザクションを終了(コミット or ロールバック)
- データベースから切断
データベースの接続はコネクションプールを利用し、
必要になった時に接続、アプリ終了時に切断という動作になります。
コネクションプールの作成と終了処理はjp.ku6.bbs.mainで行っています。
1 | ConnectionPool connectionPool = new ConnectionPool(DATABASE_PATH, DATABASE_USER, DATABASE_PASS, 10); |
---|---|
2 | scope(exit) connectionPool.shutdown(); |
トランザクションの制御はjp.ku6.bbs.logic.ThreadLogic.ThreadLogicクラスで行っています。
この辺りのクラス構成はJavaのサーブレットでよく見る形に近いかと思います。
コネクションはプールから取って使う形なので、
必要になった時に取得し、トランザクションオブジェクトにセットします。
1 | transaction_.connection = connectionPool_.lend(3); |
---|---|
2 | scope(exit) |
3 | { |
4 | connectionPool_.collect(transaction_.connection); |
5 | transaction_.connection = null; |
6 | } |
コネクションをセットしたらトランザクションを開始します。
また、終了時にコミット・例外発生時にロールバックとしています。
1 | transaction_.begin(); |
---|---|
2 | scope(failure) transaction_.rollback(); |
3 | scope(success) transaction_.commit(); |
SQLの実行はjp.ku6.bbs.dao.ThreadDao.ThreadDaoクラスで行います。
SQLの準備と終了処理は次の通りです。
1 | statement.prepare(); |
---|---|
2 | scope(exit) statement.finish(); |
今回は特に引数をセットしないのでそのまま実行します。
1 | auto result = statement.execute(); |
---|
SQLがSELECT系の場合は値を取得します。
1レコード分データを取得するには、fetchを使います。
1 | while (result.fetch()) |
---|
カラムのデータを取得するには、インデックス番号とデータ型を使って
次のように取得します。
1 | thread.id = result.get!(uint)(0); |
---|
データの表示
SQLを使って取得したデータはjp.ku6.bbs.model.Thread.Threadクラスの配列として受け取ります。
これをViewに渡し、表示処理を作成します。
表示処理については前回同様、各項目用のdelegateを作成し、
出力処理を書くだけですので、基本的にはソースを参考ください。
一点だけ特殊な箇所を説明します。ForeachProcessorテンプレートです。
1 | ForeachProcessor!(Thread) threads; |
---|
ForeachProcessor!(T)は、配列を出力するための補助処理です。
配列の個数だけ繰り返し出力処理を行うと同時に、
現在処理中の値をForeachProcessor!(T).currentにセットします。
実際のコードとは違いますが、次のような処理になっています。
1 | void process(SweetsPrinter printer, SweetsElement element, const(SweetsNode[]) children) |
---|---|
2 | { |
3 | for (index_ = 0; index_ < array.length; ++index_) |
4 | { |
5 | element.printStartTag(printer, false); |
6 | foreach (child; children) |
7 | child.print(printer); |
8 | element.printEndTag(printer); |
9 | } |
10 | } |
ForeachProcessor!(T)をセットしたタグの
子タグにセットされたdelegateは、このForeachProcessor!(T).currentにアクセスすることで、
現在の値を参照することができます。
いちいちタグ処理のdelegateを書くのは面倒極まりないので、
このように共通化出来る処理は予め作成しておくと便利です。
実行
例によってテンプレートファイルと実行ファイルを更新します。うまく表示されない場合はデータベースの接続周りを確認してみてください。
次回へ続く