DBIInterceptorをアスペクトした場合は、Pointcutに適合したメソッドが実行されます。 DBIInterceptorは、メソッドの戻り値が文字列の場合は、SQLクエリとして扱います。 メソッドの戻り値が配列の場合は、1番目の値をSQLクエリ、2番目の値をSQL発行時のコンテキストとして 扱います。
SQLクエリが取得できた場合は、データベースに発行して結果を メソッドの戻り値として return します。 データベースへのSQLクエリの発行は、DBIのPrepared Statementが使用されます。 Prepared Statementにバインド されるvalueは、メソッド引数が使用されます。メソッドの戻り値が配列の場合は、2番目の値がバインドvalueとして扱われます。
PdoInterceptorには、O/Rマップ機能や自動SQL構築機能は実装されていません。
![]() | NOTE |
|---|---|
|
DBIInterceptorの例は example/example14 にあります。 |
PrefectureテーブルにアクセスするPrefectureDaoクラスを作成します。 PrefectureDaoクラスには、Prefectureテーブルから全件を取得するfind_allメソッドを実装します。 メソッドの戻り値としてデータベースに発行するSQLクエリを返します。
module Example
class PrefectureDao
s2comp
s2aspect :interceptor => "dbi.interceptor"
def find_all
return 'select * from prefecture'
end
end
end
次の処理を行うrun.rbを作成します。
require 'rubygems'
require 'dbi'
require 's2container'
require 'seasar/dbi/interceptor'
require 'example'
s2comp(:class => DBI::DatabaseHandle, :namespace => "dbi", :autobinding => :none) {
DBI.connect("dbi:SQLite3:example.db")
}
begin
s2app[Example::PrefectureDao].find_all.each {|h|
puts "#{h['id']}\t#{h['name']}"
}
rescue Seasar::DBI::DBIInterceptor::ConnectError => e
s2logger.fatal(e.cause.class.name){"#{e.cause.message} #{e.cause.backtrace}"}
rescue => e
s2logger.fatal(e.class.name){"#{e.message} #{e.backtrace}"}
ensure
s2app[DBI::DatabaseHandle].disconnect if s2app[DBI::DatabaseHandle]
end
PrefectureテーブルにアクセスするPrefectureDaoクラスを作成します。PrefectureDaoクラスには、 PrefectureテーブルからIDで検索するfind_by_idメソッドを実装します。 find_by_idメソッドの引数で検索するIDを指定します。SQLクエリへのIDの埋め込みは、「?」で行います。
module Example
class PrefectureDao
s2comp
s2aspect :interceptor => "dbi.interceptor"
def find_by_id(id)
return 'select * from prefecture where id = ?'
end
end
end
実行ファイルは次になります。
require 'rubygems'
require 'dbi'
require 's2container'
require 'seasar/dbi/interceptor'
require 'example'
s2comp(:class => DBI::DatabaseHandle, :namespace => "dbi", :autobinding => :none) {
DBI.connect("dbi:SQLite3:example.db")
}
begin
s2app[Example::PrefectureDao].find_by_id(1).each {|h|
puts "#{h['id']}\t#{h['name']}"
}
rescue Seasar::DBI::DBIInterceptor::ConnectError => e
s2logger.fatal(e.cause.class.name){"#{e.cause.message} #{e.cause.backtrace}"}
rescue => e
s2logger.fatal(e.class.name){"#{e.message} #{e.backtrace}"}
ensure
s2app[DBI::DatabaseHandle].disconnect if s2app[DBI::DatabaseHandle]
end
PrefectureテーブルにアクセスするPrefectureDaoクラスを作成します。PrefectureDaoクラスには、 Prefectureテーブルからタイトル名で検索するfind_by_nameメソッドを実装します。 メソッドの戻り値を配列とし、1番目の値にSQLクエリ、2番目の値にSQLクエリにバインドする値を配列で指定します。
module Example
class PrefectureDao
s2comp
s2aspect :interceptor => "dbi.interceptor"
def find_by_name(name)
return "select * from prefecture where name = ?", name
end
end
end
実行ファイルは次になります。
require 'rubygems'
require 'dbi'
require 's2container'
require 'seasar/dbi/interceptor'
require 'example'
s2comp(:class => DBI::DatabaseHandle, :namespace => "dbi", :autobinding => :none) {
DBI.connect("dbi:SQLite3:example.db")
}
begin
s2app[Example::PrefectureDao].find_by_name("北海道").each {|h|
puts "#{h['id']}\t#{h['name']}"
}
rescue Seasar::DBI::DBIInterceptor::ConnectError => e
s2logger.fatal(e.cause.class.name){"#{e.cause.message} #{e.cause.backtrace}"}
rescue => e
s2logger.fatal(e.class.name){"#{e.message} #{e.backtrace}"}
ensure
s2app[DBI::DatabaseHandle].disconnect if s2app[DBI::DatabaseHandle]
end
Daoクラスの中で直接DBIを使用する場合は、DaoクラスにDBIコンポーネントをインジェクションします。 次の例では、PrefectureDaoクラスにDBI::DatabaseHandleコンポーネントをプロパティインジェクションしています。 transactional_insertメソッドでは、インジェクションされたdbhコンポーネントを使用してトランザクションを開始しています。
module Example
class PrefectureDao
s2comp
s2aspect :interceptor => "dbi.interceptor", :pointcut => /^insert/
def initialize
@dbh = :di, DBI::DatabaseHandle
end
def transactional_insert(id, name)
result = nil
@dbh['AutoCommit'] = false
begin
result = self.insert(id, name)
@dbh.commit
rescue => e
s2logger.warn(self.class.superclass.name) { "transaction failed. #{e.class.name} #{e.message}" }
@dbh.rollback
end
@dbh['AutoCommit'] = true
return result
end
def insert(id, name)
return 'insert into prefecture values(?, ?)'
end
end
end
実行ファイルは次になります。
require 'rubygems'
require 'dbi'
require 's2container'
require 'seasar/dbi/interceptor'
require 'example'
s2comp(:class => DBI::DatabaseHandle, :namespace => "dbi", :autobinding => :none) {
DBI.connect("dbi:SQLite3:example.db")
}
begin
puts s2app[Example::PrefectureDao].transactional_insert(48, "その他")
rescue Seasar::DBI::DBIInterceptor::ConnectError => e
s2logger.fatal(e.cause.class.name){"#{e.cause.message} #{e.cause.backtrace}"}
rescue => e
s2logger.fatal(e.class.name){"#{e.message} #{e.backtrace}"}
ensure
s2app[DBI::DatabaseHandle].disconnect if s2app[DBI::DatabaseHandle]
end
Seasar::DBI::Paginateクラスは、データベースからのデータ取得の際にページングを行うユーティリティクラスです。 PrefectureDaoクラスにfind_by_dtoメソッドを実装し、ページングを行います。
module Example
class PrefectureDao
s2comp
s2aspect :interceptor => "dbi.interceptor"
def find_by_dto(dto)
return "select * from prefecture where name like ? limit ? offset ?", [dto.name_like, dto.limit, dto.offset]
end
def find_total_by_dto(dto)
return "select count(*) as total from prefecture where name like ?", dto.name_like
end
end
require 'seasar/dbi/paginate'
class PrefectureDto < Seasar::DBI::Paginate
attr_accessor :name_like
end
end
次の処理を行う実行ファイルを作成します。
require 'rubygems'
require 'dbi'
require 's2container'
require 'seasar/dbi/interceptor'
require 'example'
s2comp(:class => DBI::DatabaseHandle, :namespace => "dbi", :autobinding => :none) {
DBI.connect("dbi:SQLite3:example.db")
}
begin
dto = Example::PrefectureDto.new
dto.limit = 5
dto.name_like = '%県'
dto.total = s2app[Example::PrefectureDao].find_total_by_dto(dto)[0]["total"]
puts "page : #{dto.page}"
s2app[Example::PrefectureDao].find_by_dto(dto).each {|h|
puts "#{h['id']}\t#{h['name']}"
}
dto.next
puts "page : #{dto.page}"
s2app[Example::PrefectureDao].find_by_dto(dto).each {|h|
puts "#{h['id']}\t#{h['name']}"
}
rescue Seasar::DBI::DBIInterceptor::ConnectError => e
s2logger.fatal(e.cause.class.name){"#{e.cause.message} #{e.cause.backtrace}"}
rescue => e
s2logger.fatal(e.class.name){"#{e.message} #{e.backtrace}"}
ensure
s2app[DBI::DatabaseHandle].disconnect if s2app[DBI::DatabaseHandle]
end
Seasar::DBI::Paginate#get_total_page メソッド.
全件数を件数/ページ(limit)で割った全ページ数を返します。
Seasar::DBI::Paginate#page メソッド.
現在のページ番号を返します。
Seasar::DBI::Paginate#page= メソッド.
ページ番号を設定します。
Seasar::DBI::Paginate#offset メソッド.
現在のoffset位置を返します。
Seasar::DBI::Paginate#limit= メソッド.
1ページあたりの件数を設定します。
Seasar::DBI::Paginate#total メソッド.
全件数を返します。
Seasar::DBI::Paginate#total= メソッド.
全件数を設定します。
Seasar::DBI::Paginate#window_size メソッド.
ページウィンドウに表示するページ数を設定します。
Seasar::DBI::Paginate#next メソッド.
1ページ進めます。
Seasar::DBI::Paginate#next? メソッド.
次のページがあるかどうかを返します。
Seasar::DBI::Paginate#prev メソッド.
1ページ戻ります。
Seasar::DBI::Paginate#prev? メソッド.
前のページがあるかどうかを返します。
Seasar::DBI::Paginate#page_range メソッド.
ページウィンドウ内に収まるページ番号のRangeを返します。
| © Copyright The Seasar Foundation and the others 2008-2009, all rights reserved. |