added experimental expand me...
|
1 |
=encoding utf8 |
2 | ||
updated document
|
3 |
=head1 NAME |
added experimental expand me...
|
4 | |
pod fix
|
5 |
DBIx::Custom::Guide::Ja - DBIx::Customの日本語ガイド |
added experimental expand me...
|
6 | |
7 |
=head1 ガイド |
|
8 | ||
9 |
L<DBIx::Custom>はデータベースへのクエリの発行を簡単に行うための |
|
10 |
クラスです。L<DBIx::Class>やL<DBIx::Simple>と同じように |
|
updated document
|
11 |
L<DBI>のラッパクラスになっています。L<DBIx::Class>よりも簡単に、 |
12 |
L<DBIx::Simple>よりもはるかに柔軟なことを行うことができます。 |
|
added experimental expand me...
|
13 | |
14 |
L<DBIx::Custom>はO/Rマッパーではありません。O/Rマッパーは |
|
15 |
便利ですが、O/Rマッパのたくさんの文法を覚える必要があります。 |
|
updated document
|
16 |
また、O/Rマッパによって生成されたSQLは非効率なことがありますし、 |
17 |
複雑なSQLを生成することができないので、 |
|
18 |
生のSQLを発行しなければならない場合がたくさんあります。 |
|
added experimental expand me...
|
19 | |
updated document
|
20 |
L<DBIx::Custom>はO/Rマッパとは対照的な設計が行われています。 |
updated document
|
21 |
L<DBIx::Custom>の主な目的は、SQLを尊重しつつ、L<DBI>だけでは |
updated document
|
22 |
とてもめんどうな作業を簡単にすることです。もしSQLについて |
23 |
多くの知識を持っているならば、L<DBIx::Custom>でそのまま |
|
updated document
|
24 |
活用することができます。 |
updated document
|
25 | |
26 |
L<DBIx::Custom>の仕組みを簡単に説明しておきましょう。 |
|
27 |
L<DBIx::Custom>では、タグと呼ばれるものを |
|
28 |
SQLの中に埋め込むことができます。 |
|
29 | ||
30 |
select * from book where {= title} and {=author}; |
|
31 | ||
32 |
{}で囲まれた部分がタグです。このSQLは実際に実行されるときには |
|
33 |
次のようにプレースホルダに展開されます。 |
|
34 | ||
updated document
|
35 |
select * from book where title = ? and author = ?; |
updated document
|
36 | |
37 |
これらの展開にはどのような意味があるのでしょうかと質問 |
|
updated document
|
38 |
されることかと思います。この簡単な仕組みの上に非常にたくさんの |
39 |
有用で便利で使いやすい機能が構築されます。それは以下のようなものです。 |
|
updated document
|
40 | |
updated document
|
41 |
=over 4 |
updated document
|
42 | |
updated document
|
43 |
=item 1. プレースホルダのパラメータをハッシュリファレンスで指定 |
updated document
|
44 | |
updated document
|
45 |
L<DBI>をそのまま使うのであればプレースホルダのパラメータは配列 |
46 |
で指定する必要があります。 |
|
updated document
|
47 | |
updated document
|
48 |
$sth->execute(@bind); |
49 | ||
50 |
L<DBIx::Custom>を利用するのであればハッシュリファレンスで指定すること |
|
51 |
できます。 |
|
52 |
|
|
53 |
my $param = {title => 'Perl', author => 'Ken'}; |
|
54 |
$dbi->execute($sql, $param); |
|
55 | ||
56 |
=item 2. パラメータのフィルタリング |
|
57 | ||
58 |
たとえば、日付の列は、Perlで扱うときにはC<Time::Piece>などの日付オブジェクト |
|
59 |
で扱い、データベースに格納するときはデータベースの日付型に変換したい |
|
60 |
と思うのではないでしょうか。またデータベースから取り出すときは |
|
61 |
データベースの日付型から日付オブジェクトに変換したと思うのでは |
|
62 |
ないでしょうか。 |
|
63 | ||
64 |
このようなときはフィルタ機能を使うことができます。 |
|
65 | ||
66 |
まずフィルタを登録します。 |
|
67 | ||
68 |
$dbi->register_filter( |
|
69 |
tp_to_date => sub { |
|
70 |
... |
|
71 |
}, |
|
72 |
date_to_tp => sub { |
|
73 |
... |
|
74 |
} |
|
75 |
); |
|
76 | ||
77 |
次にテーブルの各列にこのフィルタを適用します。 |
|
78 | ||
79 |
$dbi->apply_filter('book', |
|
80 |
'publish_date' => {out => 'tp_to_date', in => 'date_to_tp'} |
|
81 |
); |
|
82 | ||
83 |
outはPerlからデータベースに保存する方向、inはデータベースからPerlに取得する方向です。 |
|
84 | ||
85 |
SQLを発行するときにテーブルの指定を行えば、自動的にこのフィルタが適用されます。 |
|
86 | ||
87 |
$dbi->execute($sql, $param, table => 'book'); |
|
88 | ||
89 |
=item 3. 選択的な検索条件 |
|
90 | ||
91 |
生のDBIを利用しているとき一番たいへんなのは選択的な検索条件を作成したいときです。 |
|
92 | ||
93 |
たとえば、検索条件にtitleとauthorが指定された場合は次のSQLを |
|
94 | ||
95 |
select * from book where title = ? and author = ?; |
|
96 | ||
97 |
titleだけの場合は次のSQLを |
|
98 | ||
99 |
select * from book where title = ?; |
|
100 |
|
|
101 |
authorだけの場合は次のSQLを発行した場合を考えましょう。 |
|
102 | ||
103 |
select * from book where author = ?; |
|
104 | ||
105 |
これはとても大変な作業なので、通常はL<SQL::Abstract>を動的に生成してくれる |
|
106 |
モジュールを利用することになります。 |
|
107 | ||
108 |
L<DBIx::Custom>はさらに簡単で便利な方法を用意しています。 |
|
109 | ||
110 |
my $where = $dbi->where; |
|
111 |
$where->param({title => 'Perl'}); |
|
112 |
$where->clause( |
|
113 |
['and', '{= title}', {'= author'}] |
|
114 |
); |
|
115 | ||
116 |
my $sql = "select * from book $where"; |
|
117 | ||
118 |
詳しい説明は後ほど行いますが、上記のように記述すれば、 |
|
119 |
L<DBIx::Custom>では選択的な検索条件を持つWhere句を生成することができます。 |
|
120 |
検索条件が入れ子になった構造やorについても対応しています。 |
|
121 | ||
122 |
=item 4. 挿入、更新、削除、選択を行うためのメソッド |
|
123 | ||
124 |
L<DBIx::Custom>ではSQLをさらに簡単に実行するための |
|
125 |
メソッドも提供しています。 |
|
added experimental expand me...
|
126 |
C<insert()>, C<update()>, C<delete()>,C<select()>などの |
updated document
|
127 |
シュガーメソッドを使って、挿入、更新、削除、選択という操作を行うことが |
128 |
できます。 |
|
129 | ||
130 |
my $param = {title => 'Perl', author => 'Ken'}; |
|
131 |
$dbi->insert(table => 'book', param => $param); |
|
132 | ||
133 |
=item 5. テーブル単位の操作の登録 |
|
134 | ||
135 |
テーブルに対して操作を登録することができます。これによって |
|
136 |
テーブル名を繰り返し指定する必要がなくなり、ソースコードの |
|
137 |
見通しが良くなります。 |
|
138 | ||
139 |
$dbi->talbe('book', |
|
140 |
list => sub { |
|
141 |
... |
|
142 |
}, |
|
143 |
list_somethin => sub { |
|
144 |
|
|
145 |
} |
|
146 |
); |
|
147 | ||
148 |
登録したメソッドはそのまま利用することができます。 |
|
149 | ||
150 |
$dbi->table('book')->list; |
|
added experimental expand me...
|
151 | |
updated document
|
152 |
通常O/Rマッパはテーブルに対応するクラスを作成しなければ |
153 |
ならないことが多いですが、L<DBIx::Custom>ではこの作業を簡便に |
|
154 |
しており、上記のように登録することができます。 |
|
added experimental expand me...
|
155 | |
updated document
|
156 |
=back |
157 | ||
158 |
L<DBIx::Custom>はL<DBI>を補うとても便利なモジュールです。 |
|
159 |
興味をもたれた方は、この後で詳しい解説を行いますので、 |
|
160 |
ご覧になってみてください。 |
|
added experimental expand me...
|
161 | |
162 |
=head2 1. データベースへの接続 |
|
163 | ||
updated document
|
164 |
まずL<DBIx::Custom>を読み込みます。 |
165 | ||
166 |
use DBIx::Custom; |
|
167 | ||
added experimental expand me...
|
168 |
L<DBIx::Custom>オブジェクトを生成し、データベースに接続するには |
169 |
C<connect()>メソッドを使用します。 |
|
170 | ||
updated document
|
171 |
my $dbi = DBIx::Custom->connect( |
172 |
data_source => "dbi:mysql:database=dbname", |
|
173 |
user => 'ken', |
|
174 |
password => '!LFKD%$&', |
|
175 |
dbi_options => {mysql_enable_utf8 => 1} |
|
176 |
); |
|
added experimental expand me...
|
177 | |
updated document
|
178 |
C<data_source>はデータベースシステムに応じたフォーマットで |
179 |
指定する必要があります。以下にデータベースごとのフォーマット |
|
180 |
方法のサンプルを掲載しておきます。 |
|
added experimental expand me...
|
181 | |
updated document
|
182 |
B<MySQL> |
added experimental expand me...
|
183 | |
deprecated DBIx::Custom::MyS...
|
184 |
"dbi:mysql:database=$database" |
185 |
"dbi:mysql:database=$database;host=$hostname;port=$port" |
|
added experimental expand me...
|
186 | |
updated document
|
187 |
B<SQLite> |
deprecated DBIx::Custom::MyS...
|
188 | |
189 |
"dbi:SQLite:dbname=$database" |
|
190 |
"dbi:SQLite:dbname=:memory:" |
|
191 | ||
updated document
|
192 |
B<PostgreSQL> |
deprecated DBIx::Custom::MyS...
|
193 | |
194 |
"dbi:Pg:dbname=$dbname" |
|
195 | ||
updated document
|
196 |
B<Oracle> |
deprecated DBIx::Custom::MyS...
|
197 | |
198 |
"dbi:Oracle:$dbname" |
|
199 |
"dbi:Oracle:host=$host;sid=$sid" |
|
200 | ||
updated document
|
201 |
B<ODBC(Microsoft Access)> |
deprecated DBIx::Custom::MyS...
|
202 | |
203 |
"dbi:ODBC:driver=Microsoft Access Driver (*.mdb);dbq=hoge.mdb" |
|
204 | ||
updated document
|
205 |
B<ODBC(SQL Server)> |
deprecated DBIx::Custom::MyS...
|
206 | |
207 |
"dbi:ODBC:driver={SQL Server};Server=(local);database=test;Trusted_Connection=yes;AutoTranslate=No;" |
|
added experimental expand me...
|
208 | |
updated document
|
209 |
また認証が求められる場合は、C<user>とC<password>ユーザ名と |
210 |
パスワードを指定する必要があります。 |
|
211 | ||
added experimental expand me...
|
212 |
L<DBIx::Custom>はL<DBI>のラッパです。 |
updated document
|
213 |
L<DBI>のデータベースハンドルはC<dbh>で取得することができます。 |
added experimental expand me...
|
214 | |
215 |
my $dbh = $dbi->dbh; |
|
216 | ||
updated document
|
217 |
L<DBIx::Custom>ではデータベースハンドル属性にはデフォルトで次のものが設定されます。 |
added experimental expand me...
|
218 |
|
219 |
$dbi->dbh->{RaiseError} = 1; |
|
220 |
$dbi->dbh->{PrintError} = 0; |
|
221 |
$dbi->dbh->{AutoCommit} = 1; |
|
222 | ||
223 |
この設定を行っているので、致命的なエラーが起こると、 |
|
224 |
例外が発生しプログラムは終了します。 |
|
225 |
またクエリが発行されると自動的にコミットされます。 |
|
226 | ||
updated document
|
227 |
=head2 2. 挿入、更新、削除、選択のためのメソッド |
added experimental expand me...
|
228 | |
229 |
L<DBIx::Custom>は、 |
|
230 |
C<insert()>、C<update()>、C<delete()>、C<select()> |
|
updated document
|
231 |
のような挿入、更新、削除、選択を行うためのメソッドを持っています。 |
232 |
簡単なことをを行うのであれば、SQLを自分で記述する必要がありません。 |
|
added experimental expand me...
|
233 | |
234 |
=head3 C<insert()> |
|
235 | ||
updated document
|
236 |
データベースにデータを挿入するにはC<insert()>を使用します。 |
added experimental expand me...
|
237 | |
remove DBIx::Custom::Model
|
238 |
$dbi->insert(table => 'book', |
added experimental expand me...
|
239 |
param => {title => 'Perl', author => 'Ken'}); |
240 | ||
updated document
|
241 |
C<table>にはテーブル名、C<param>には挿入したいデータを指定します。 |
added experimental expand me...
|
242 | |
updated document
|
243 |
次のSQLが発行されます。 |
244 | ||
245 |
insert into (title, author) values (?, ?); |
|
added experimental expand me...
|
246 | |
247 |
=head3 C<update()> |
|
248 | ||
updated document
|
249 |
データベースのデータを更新するには、C<update()>を使用します。 |
added experimental expand me...
|
250 | |
remove DBIx::Custom::Model
|
251 |
$dbi->update(table => 'book', |
added experimental expand me...
|
252 |
param => {title => 'Perl', author => 'Ken'}, |
253 |
where => {id => 5}); |
|
254 | ||
updated document
|
255 |
C<table>にはテーブル名、C<param>には挿入したいデータ、C<where>には |
256 |
条件を指定します。 |
|
added experimental expand me...
|
257 | |
updated document
|
258 |
次のSQLが発行されます。 |
259 | ||
260 |
update book set title = ?, author = ?; |
|
added experimental expand me...
|
261 | |
262 |
C<update>メソッドは安全のため |
|
263 |
where句のないSQLを発行することを許可していません。 |
|
264 |
もしすべての行を更新したい場合は |
|
updated document
|
265 |
C<update_all()>を使用してください。 |
added experimental expand me...
|
266 | |
remove DBIx::Custom::Model
|
267 |
$dbi->update_all(table => 'book', |
added experimental expand me...
|
268 |
param => {title => 'Perl', author => 'Ken'}); |
269 | ||
270 |
=head3 C<delete()> |
|
271 | ||
updated document
|
272 |
データベースのデータを1件削除するには、C<delete()>を使用します。 |
added experimental expand me...
|
273 | |
remove DBIx::Custom::Model
|
274 |
$dbi->delete(table => 'book', |
added experimental expand me...
|
275 |
where => {author => 'Ken'}); |
276 | ||
updated document
|
277 |
C<table>にはテーブル名、C<where>には条件を指定します。 |
added experimental expand me...
|
278 | |
updated document
|
279 |
次のSQLが発行されます。 |
280 | ||
281 |
delete from book where id = ?; |
|
added experimental expand me...
|
282 | |
283 |
C<delete>メソッドは安全のため |
|
284 |
where句のないSQLを発行することを許可していません。 |
|
285 |
もしすべての行を削除したい場合は |
|
updated document
|
286 |
C<delete_all()>を使用してください。 |
added experimental expand me...
|
287 | |
remove DBIx::Custom::Model
|
288 |
$dbi->delete_all(table => 'book'); |
added experimental expand me...
|
289 | |
290 |
=head3 C<select()> |
|
291 | ||
updated document
|
292 |
行を選択するにはC<select()>を使用します。 |
added experimental expand me...
|
293 | |
remove DBIx::Custom::Model
|
294 |
my $result = $dbi->select(table => 'book'); |
added experimental expand me...
|
295 | |
updated document
|
296 |
C<table>だけを指定して、他の条件を指定しない場合は次のSQLが発行されます。 |
added experimental expand me...
|
297 | |
updated document
|
298 |
select * from book; |
added experimental expand me...
|
299 | |
300 |
C<select()>メソッドの戻り値はL<DBIx::Custom::Result> |
|
updated document
|
301 |
オブジェクトです。行をフェッチするにはC<fetch()>を使用します。 |
added experimental expand me...
|
302 | |
303 |
while (my $row = $result->fetch) { |
|
304 |
my $title = $row->[0]; |
|
305 |
my $author = $row->[1]; |
|
306 |
} |
|
307 | ||
updated document
|
308 |
L<DBIx::Custom::Result>についてはこの後L<3. 行のフェッチ/"3. 行のフェッチ">で詳しく扱います。 |
309 | ||
310 |
さまざまなC<select()>の使い方を見ていきましょう。 |
|
added experimental expand me...
|
311 |
次のC<select>は行の名前とwhere句を指定したものです。 |
312 | ||
313 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
314 |
table => 'book', |
updated document
|
315 |
column => ['author', 'title'], |
added experimental expand me...
|
316 |
where => {author => 'Ken'} |
317 |
); |
|
318 | ||
updated document
|
319 |
C<column>には列名を、C<where>には条件を指定することができます。 |
320 |
次のSQLが発行されます。 |
|
321 | ||
322 |
select author, title from book where author = ?; |
|
added experimental expand me...
|
323 | |
updated document
|
324 |
テーブルを結合したい場合ははC<relation>にテーブルの |
325 |
関係を記述します。 |
|
added experimental expand me...
|
326 | |
327 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
328 |
table => ['book', 'rental'], |
updated document
|
329 |
where => {book.name => 'Perl'}, |
remove DBIx::Custom::Model
|
330 |
relation => {'book.id' => 'rental.book_id'} |
added experimental expand me...
|
331 |
); |
332 | ||
updated document
|
333 |
bookテーブルのid列とrentalテーブルのbook_idが関連付けられます。 |
334 |
次のSQLが発行されます。 |
|
added experimental expand me...
|
335 | |
updated document
|
336 |
select * from book, rental where book.name = ? and book.id = rental.book_id; |
added experimental expand me...
|
337 | |
updated document
|
338 |
SQL文の末尾に文字列を追加したい場合は<append>を使用します。 |
added experimental expand me...
|
339 | |
340 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
341 |
table => 'book', |
added experimental expand me...
|
342 |
where => {author => 'Ken'}, |
updated document
|
343 |
append => 'for update', |
added experimental expand me...
|
344 |
); |
345 | ||
updated document
|
346 |
次のSQLが発行されます。 |
updated document
|
347 | |
updated document
|
348 |
select * book where author = ? for update; |
updated document
|
349 | |
updated document
|
350 |
またC<append>は、C<select>だけでなくC<insert()>、C<update()>、C<update_all()> |
351 |
C<delete()>、C<delete_all()>、C<select()>で使用することもできます。 |
|
updated document
|
352 | |
353 |
=head2 3. 行のフェッチ |
|
354 | ||
updated document
|
355 |
C<select()>メソッドの戻り値はL<DBIx::Custom::Result>オブジェクトです。 |
356 |
L<DBIx::Custom::Result>には行をフェッチするためのさまざまなメソッドが |
|
updated document
|
357 |
用意されています。 |
358 | ||
359 |
=head3 C<fetch> |
|
360 | ||
updated document
|
361 |
一行フェッチして配列のリファレンスに格納するにはC<fetch()>を使用します。 |
updated document
|
362 | |
363 |
while (my $row = $result->fetch) { |
|
updated document
|
364 |
my $title = $row->[0]; |
365 |
my $author = $row->[1]; |
|
updated document
|
366 |
} |
367 | ||
updated document
|
368 |
whileループを使って、すべての行を取得することができます。 |
369 | ||
updated document
|
370 |
=head3 C<fetch_first> |
371 | ||
updated document
|
372 |
一行だけフェッチして配列のリファレンスに格納するにはC<fetch_first()> |
373 |
を使用します。 |
|
updated document
|
374 | |
375 |
my $row = $result->fetch_first; |
|
376 | ||
updated document
|
377 |
一行のフェッチが終わった後はそれ以上フェッチできなくなります。 |
378 |
内部的には1行のフェッチが終わった後に |
|
379 |
ステートメントハンドルのC<finish()>が実行されます。 |
|
updated document
|
380 | |
381 |
=head3 C<fetch_multi> |
|
382 | ||
updated document
|
383 |
複数行をフェッチして配列のリファレンスを要素に持つ |
384 |
配列のリファレンスに格納するにはC<fetch_multi()>を使用します。 |
|
updated document
|
385 | |
updated document
|
386 |
while (my $rows = $result->fetch_multi(2)) { |
387 |
my $title0 = $rows->[0][0]; |
|
388 |
my $author0 = $rows->[0][1]; |
|
389 |
|
|
390 |
my $title1 = $rows->[1][0]; |
|
391 |
my $author1 = $rows->[1][1]; |
|
updated document
|
392 |
} |
393 | ||
updated document
|
394 |
引数には取り出したい行数を指定します。 |
395 | ||
396 |
指定した行を格納した次のようなデータを取得できます。 |
|
397 | ||
398 |
[ |
|
399 |
['Perl', 'Ken'], |
|
400 |
['Ruby', 'Mark'] |
|
401 |
] |
|
402 | ||
updated document
|
403 |
=head3 C<fetch_all> |
404 | ||
updated document
|
405 |
すべての行をフェッチして配列のリファレンスを要素に持つ |
406 |
配列のリファレンスに格納するにはC<fetch_all()>を使用します。 |
|
updated document
|
407 | |
408 |
my $rows = $result->fetch_all; |
|
409 | ||
updated document
|
410 |
すべての行を格納した次のようなデータを取得できます。 |
411 | ||
412 |
[ |
|
413 |
['Perl', 'Ken'], |
|
414 |
['Ruby', 'Mark'] |
|
415 |
] |
|
416 | ||
updated document
|
417 |
=head3 C<fetch_hash> |
418 | ||
updated document
|
419 |
一行フェッチしてハッシュのリファレンスに格納するにはC<fetch_hash()>を使用します。 |
updated document
|
420 | |
421 |
while (my $row = $result->fetch_hash) { |
|
422 |
my $title = $row->{title}; |
|
423 |
my $author = $row->{author}; |
|
424 |
} |
|
425 | ||
426 |
=head3 C<fetch_hash_first> |
|
427 | ||
updated document
|
428 |
一行だけフェッチしてハッシュのリファレンスに格納するには |
429 |
C<fetch_hash_first()>を使用します。 |
|
updated document
|
430 | |
431 |
my $row = $result->fetch_hash_first; |
|
432 | ||
updated document
|
433 |
一行のフェッチが終わった後はそれ以上フェッチできなくなります。 |
434 |
内部的には1行のフェッチが終わった後に |
|
435 |
ステートメントハンドルのC<finish()>が実行されます。 |
|
updated document
|
436 | |
437 |
=head3 C<fetch_hash_multi> |
|
438 | ||
updated document
|
439 |
複数行をフェッチしてハッシュのリファレンスを要素に持つ |
440 |
配列のリファレンスに格納するにはC<fetch_hash_multi()> |
|
441 |
を使用します。 |
|
updated document
|
442 | |
443 |
while (my $rows = $result->fetch_hash_multi(5)) { |
|
updated document
|
444 |
my $title0 = $rows->[0]{title}; |
445 |
my $author0 = $rows->[0]{author}; |
|
446 |
my $title1 = $rows->[1]{title}; |
|
447 |
my $author1 = $rows->[1]{author}; |
|
updated document
|
448 |
} |
449 | ||
updated document
|
450 |
引数には取り出したい行数を指定します。 |
451 | ||
452 |
指定した行を格納した次のようなデータを取得できます。 |
|
453 | ||
454 |
[ |
|
455 |
{title => 'Perl', author => 'Ken'}, |
|
456 |
{title => 'Ruby', author => 'Mark'} |
|
457 |
] |
|
458 | ||
updated document
|
459 |
=head3 C<fetch_all> |
460 | ||
updated document
|
461 |
すべての行をフェッチしてハッシュのリファレンスを要素に持つ |
462 |
配列のリファレンスに格納するにはC<fetch_hash_all()> |
|
463 |
を使用します。 |
|
updated document
|
464 | |
465 |
my $rows = $result->fetch_hash_all; |
|
466 | ||
updated document
|
467 |
すべての行を格納した次のようなデータを取得できます。 |
468 | ||
469 |
[ |
|
470 |
{title => 'Perl', author => 'Ken'}, |
|
471 |
{title => 'Ruby', author => 'Mark'} |
|
472 |
] |
|
473 | ||
474 |
=head3 sth |
|
475 | ||
476 |
ステートメントハンドルに直接アクセスしたい場合は |
|
477 |
<sth>で取得することができます。 |
|
updated document
|
478 | |
479 |
my $sth = $result->sth; |
|
480 | ||
updated document
|
481 |
フェッチのパフォーマンスが用件を満たさないときには、 |
482 |
ステートメントハンドルから |
|
483 |
利用できる速度の速いメソッドを利用することができます。 |
|
484 | ||
485 |
=head2 4. タグ |
|
updated document
|
486 | |
487 |
L<DBIx::Custom>はハッシュパラメタバインドを提供します。 |
|
488 | ||
489 |
まず最初にL<DBI>による通常のパラメタバインドをご覧ください。 |
|
490 | ||
491 |
use DBI; |
|
492 |
my $dbh = DBI->connect(...); |
|
493 |
my $sth = $dbh->prepare( |
|
494 |
"select * from book where author = ? and title like ?;" |
|
495 |
); |
|
496 |
$sth->execute('Ken', '%Perl%'); |
|
497 | ||
498 |
これはデータベースシステムがSQLをキャッシュすることができ、 |
|
499 |
パラメータは自動的にクォートされるので、 |
|
500 |
パフォーマンス面でも、セキュリティ面でも |
|
501 |
とても良い方法です。 |
|
502 | ||
503 | ||
504 |
L<DBIx::Custom>はこれを改善して、ハッシュで |
|
505 |
パラメタを指定できるようにしました。 |
|
506 | ||
507 |
my $result = $dbi->execute( |
|
508 |
"select * from book where {= author} and {like title};" |
|
509 |
param => {author => 'Ken', title => '%Perl%'} |
|
510 |
); |
|
511 | ||
512 |
C<{= author}>とC<{like title}>はタグと呼ばれます。 |
|
513 |
タグは内部ではプレースホルダを含む文字列に置き換えられます。 |
|
514 | ||
515 |
select * from book where {= author} and {like title} |
|
516 | ||
517 |
という文は以下のSQLに置き換えられます。 |
|
518 | ||
519 |
select * from book where author = ? and title like ?; |
|
520 | ||
521 |
このようにタグを使ってSQL文を表現するのがL<DBIx::Custom>の |
|
522 |
特徴です。以下のタグが利用可能です。 |
|
523 | ||
524 |
[TAG] [REPLACED] |
|
525 |
{? NAME} -> ? |
|
526 |
{= NAME} -> NAME = ? |
|
527 |
{<> NAME} -> NAME <> ? |
|
528 |
|
|
529 |
{< NAME} -> NAME < ? |
|
530 |
{> NAME} -> NAME > ? |
|
531 |
{>= NAME} -> NAME >= ? |
|
532 |
{<= NAME} -> NAME <= ? |
|
533 |
|
|
534 |
{like NAME} -> NAME like ? |
|
535 |
{in NAME COUNT} -> NAME in [?, ?, ..] |
|
536 |
|
|
537 |
{insert_param NAME1 NAME2} -> (NAME1, NAME2) values (?, ?) |
|
538 |
{update_param NAME1 NAME2} -> set NAME1 = ?, NAME2 = ? |
|
539 | ||
540 |
これらの変換はL<DBIx::Custom::QueryBuilder>によって行われます。 |
|
541 | ||
542 |
C<{>とC<}>は予約語です。これらの文字を使いたい場合は |
|
543 |
「\」を使ってエスケープする必要があります。 |
|
544 |
'\'はPerlのエスケープ文字なので、 |
|
545 |
エスケープするためには'\\'と書く必要があることに注意 |
|
546 |
してください。 |
|
547 | ||
548 |
'select * from book \\{ something statement \\}' |
|
549 | ||
550 |
=head2 5. フィルタリング |
|
551 | ||
552 |
=head3 パラメタバインド時のフィルタリング |
|
553 | ||
554 |
データベースに登録するデータをフィルタリングしたい場合 |
|
555 |
があります。たとえば、内部文字列で文字列を保持している場合は |
|
556 |
データベースにデータを登録する前に、バイト文字列に変換する |
|
557 |
必要があります。L<DBIx::Custom>のフィルタリングシステムは |
|
558 |
あるデータを他のデータに変換するのを手助けしてくれます。 |
|
559 | ||
560 |
フィルタリングを利用するにはまず、 |
|
561 |
C<register_filter()>メソッドを使用して |
|
562 |
フィルタを登録しておく必要があります。 |
|
563 | ||
564 |
$dbi->register_filter( |
|
565 |
to_upper_case => sub { |
|
566 |
my $value = shift; |
|
567 |
return uc $value; |
|
568 |
} |
|
569 |
); |
|
570 | ||
571 |
デフォルトのフィルタとしてC<encode_utf8>とC<decode_utf8> |
|
572 |
が登録されています。 |
|
573 | ||
574 |
登録されているフィルタはC<execute()>メソッドのC<filter>オプション |
|
575 |
で指定することができます。 |
|
576 | ||
577 |
my $result = $dbi->execute( |
|
578 |
"select * from book where {= author} and {like title};" |
|
579 |
param => {author => 'Ken', title => '%Perl%'}, |
|
580 |
filter => {author => 'to_upper_case, title => 'encode_utf8'} |
|
581 |
); |
|
582 | ||
583 |
この例ではC<author>の値はバインドされるときに大文字に変換され、 |
|
584 |
C<title>の値はバイト文字列に変換されます。 |
|
585 | ||
586 |
C<filter>オプションは |
|
587 |
C<insert()>、C<update()>、 C<update_all()>, |
|
588 |
C<delete()>、C<select()> |
|
589 |
メソッドにおいても使用することができます。 |
|
590 | ||
591 |
# insert() with filter option |
|
592 |
$dbi->insert(table => 'book', |
|
593 |
param => {title => 'Perl', author => 'Ken'}, |
|
594 |
filter => {title => 'encode_utf8'}); |
|
595 |
|
|
596 |
# select() with filter option |
|
597 |
my $result = $dbi->select( |
|
598 |
table => 'book', |
|
599 |
column => [qw/author title/], |
|
600 |
where => {author => 'Ken'}, |
|
601 |
append => 'order by id limit 1', |
|
602 |
filter => {title => 'encode_utf8'} |
|
603 |
); |
|
604 | ||
605 |
=head3 行のフェッチ時のフィルタリング |
|
606 | ||
607 |
行をフェッチするときのフィルタも設定することができます。 |
|
608 |
これはL<DBIx::Custom::Result>クラスのC<filter>メソッドを使って |
|
609 |
行います。 |
|
610 | ||
611 |
my $result = $dbi->select(table => 'book'); |
|
612 |
$result->filter({title => 'decode_utf8', author => 'to_upper_case'}); |
|
613 | ||
614 |
フェッチのためのフィルタにおいて、 |
|
615 |
たとえ、列名が大文字を含む場合であっても |
|
616 |
列名は小文字であることに注意してください。 |
|
617 |
これはデータベースシステムに依存させないための要件です。 |
|
618 | ||
619 |
=head2 6. パフォーマンスの改善 |
|
620 | ||
621 |
=head3 シュガーメソッドを使わない |
|
622 | ||
623 |
もしC<insert()>メソッドを使用してインサートを実行した場合、 |
|
624 |
必要なパフォーマンスを得られない場合があるかもしれません。 |
|
625 |
C<insert()>メソッドは、SQL文とステートメントハンドルを |
|
626 |
毎回作成するためすこし遅いです。 |
|
627 | ||
628 |
そのような場合は、C<create_query()>メソッドによって |
|
629 |
クエリを用意しておくことができます。 |
|
630 |
|
|
631 |
my $query = $dbi->create_query( |
|
632 |
"insert into book {insert_param title author};" |
|
633 |
); |
|
634 | ||
635 |
戻り値はL<DBIx::Custom::Query>オブジェクトです。 |
|
636 |
このオブジェクトはSQL文とパラメータバインド時の列名を |
|
637 |
保持しています。またステートメントハンドルも保持しています。 |
|
638 | ||
639 |
{ |
|
640 |
sql => 'insert into book (title, author) values (?, ?);', |
|
641 |
columns => ['title', 'author'], |
|
642 |
sth => $sth |
|
643 |
} |
|
644 | ||
645 |
クエリオブジェクトを使って繰り返し実行するには次のようにします。 |
|
646 |
|
|
647 |
my $inputs = [ |
|
648 |
{title => 'Perl', author => 'Ken'}, |
|
649 |
{title => 'Good days', author => 'Mike'} |
|
650 |
]; |
|
651 |
|
|
652 |
foreach my $input (@$inputs) { |
|
653 |
$dbi->execute($query, $input); |
|
654 |
} |
|
655 | ||
656 |
C<execute>メソッドの第一引数にクエリオブジェトを渡すことができます。 |
|
657 |
これはC<insert()>メソッドよりも高速です。 |
|
658 | ||
659 |
=head2 7. その他の機能 |
|
660 | ||
661 |
=head3 トランザクション |
|
662 | ||
663 |
トランザクションを便利に利用するために、 |
|
664 |
C<begin_work()>、C<commit()>、C<rollback()> |
|
665 |
という三つのメソッドが容易されています。 |
|
666 |
これはL<DBI>の同名のメソッドと同じ機能を持ちます。 |
|
667 | ||
668 |
$dbi->begin_work; |
|
669 |
|
|
670 |
eval { |
|
671 |
$dbi->update(...); |
|
672 |
$dbi->update(...); |
|
673 |
}; |
|
674 |
|
|
675 |
if ($@) { |
|
676 |
$dbi->rollback; |
|
677 |
} |
|
678 |
else { |
|
679 |
$dbi->commit; |
|
680 |
} |
|
681 | ||
682 |
=head3 selectメソッドの結果クラスの変更 |
|
683 | ||
684 |
必要ならばC<select()>メソッドの結果クラスを変更することができます。 |
|
685 | ||
686 |
package Your::Result; |
|
687 |
use base 'DBIx::Custom::Result'; |
|
688 |
|
|
689 |
sub some_method { ... } |
|
690 | ||
691 |
1; |
|
692 |
|
|
693 |
package main; |
|
694 |
|
|
695 |
use Your::Result; |
|
696 |
|
|
697 |
my $dbi = DBIx::Custom->connect(...); |
|
698 |
$dbi->result_class('Your::Result'); |
|
699 | ||
700 |
=head3 L<DBIx::Custom::QueryBuilder>の機能の拡張 |
|
701 | ||
702 |
新しいタグが欲しい場合はL<DBIx::Custom::QueryBuilder>の機能を拡張 |
|
703 |
することができます。 |
|
704 | ||
705 |
my $dbi = DBIx::Custom->connect(...); |
|
706 |
$dbi->query_builder->register_tag_processor( |
|
707 |
name => sub { |
|
708 |
... |
|
709 |
} |
|
710 |
); |
|
711 | ||
712 |
=head3 ヘルパーメソッドの登録 |
|
713 | ||
714 |
ヘルパーメソッドを登録することができます。 |
|
715 | ||
716 |
$dbi->helper( |
|
717 |
update_or_insert => sub { |
|
718 |
my $self = shift; |
|
719 |
# do something |
|
720 |
}, |
|
721 |
find_or_create => sub { |
|
722 |
my $self = shift; |
|
723 |
# do something |
|
724 |
} |
|
725 |
); |
|
726 | ||
727 |
<helper()>メソッドで登録したメソッドは |
|
728 |
L<DBIx::Custom>オブジェクトから直接呼び出すことができます。 |
|
729 | ||
730 |
$dbi->update_or_insert; |
|
731 |
$dbi->find_or_create; |
|
732 | ||
733 |
=head3 ユーティリティメソッド(実験的) |
|
734 | ||
735 |
C<expand>メソッドを使用すると次のようなハッシュに含まれる |
|
736 |
テーブル名と列名を結合することができます。 |
|
737 | ||
738 |
my %expanded = $dbi->expand(\%source); |
|
739 | ||
740 |
以下のハッシュ |
|
741 | ||
742 |
{book => {title => 'Perl', author => 'Ken'}} |
|
743 | ||
744 |
は次のように展開されます。 |
|
745 | ||
746 |
('book.title' => 'Perl', 'book.author' => 'Ken') |
|
747 | ||
748 |
これはテーブル名を含むselect文で利用すると便利です。 |
|
749 | ||
750 |
my $param = {title => 'Perl', author => '%Ken%'}; |
|
751 |
$dbi->execute( |
|
752 |
'select * from book where {= book.title} && {like book.author};', |
|
753 |
param => {$dbi->expand({book => $param})} |
|
754 |
); |
|
755 | ||
756 |
=cut |