ビギナーだから使いたいo/rマッパー ~tengを使った開発~
DESCRIPTION
Perl Beginners#3で発表したSQL/DB初心者向けのPerlのO/RマッパーTengの使い方のチュートリアルです。TRANSCRIPT
ビギナーだから使いたいO/Rマッパー ~Tengを使った開発~
Hirobanex(Akabane Hiroyuki)
2012-06-29@Perl Beginners #3
1
コンテンツ
• Tengを使いたい3つの理由 • ビギナーにオススメのTengの導入方法 • 本来のO/Rマッパーの効用
2
Tengを使いたい3つの理由
• DBIはよくわからん • O/Rマッパーだと開発が抜群に早くなる • コード量が少ないし、勉強になる
3
生DBIはよくわからん
• コンストラクション時の設定って? • セレクト系メソッドどれ使えばいい? • ドキュメントが長すぎてどこ読めば? • トランザクションって? • 突然、コネクション切れる?
4
セレクト系メソッドどれ使えばいい?
•fetchrow_arrayref •fetchrow_array •fetchrow_hashref •fetchall_arrayref •fetchall_hashref
•selectrow_array •selectrow_arrayref •selectrow_hashref •selectall_arrayref •selectall_hashref •selectcol_arrayref
refとかarrayとかhashとか、頭がパンクします・・・
5
O/Rマッパーだと開発が抜群に早くなる
use DBI; my @data_set = ( [26,'hiro'], [27,'bane'], ); my $dbh = DBI->connect("DBI:mysql:db_name;", "root", "pass",{ AutoCommit => 0, }); for my $data (@data_set) { my ($age,$name) = @$data; my ($age_id) = $dbh->selectrow_array(q{ SELECT id FROM age WHERE age = ? },undef,$age); unless ($age_id) { my $sth = $dbh->prepare(q{ INSERT INTO age (age) VALUES ( ? ) }); $sth->execute($age); #mysql限定 $age_id = $dbh->last_insert_id(undef, undef, 'age', 'id'); } my $sth = $dbh->prepare(q{ INSERT INTO user (age_id, name) VALUES (?, ?) }); $sth->execute($age_id, $name); } $dbh->do('COMMIT');
#Teng-0.14_05 use DBI; use Teng; use Teng::Schema::Loader; my @data_set = ( [26,'hiro'], [27,'bane'], ); my $dbh = DBI->connect("DBI:mysql:db_name;", "root", "pass",); my $teng = Teng::Schema::Loader->load( dbh => $dbh, namespace => 'MyAPP::DB', ); $teng->load_plugin('FindOrCreate'); my $txn = $teng->txn_scope; for my $data (@data_set) { my ($age,$name) = @$data; my $row = $teng->find_or_create('age',{ age => $age }); $teng->insert('user', { age_id => $row->id, name => $name }); } $txn->commit;
DBI Teng
複数データ群をリレーションつけて登録する場合のコード比較
20行 7行
6
コード量が少ないし、勉強になる
• オーサーは日本人のnekokakさん • 不明点は誰かに聞けばわかりそう • 日本語情報豊富 • 挙動確認がコード量が少ないため楽 • コードをおうと、Perlの勉強になる
7
ビギナーにオススメのTengの導入方法
• Tengのnew(オブジェクトの作り方) • SELECT • INSERT、UPDATE、DELETE • トランザクション
DBIもよくわからんけど、とにかく早く使ってみたい人向け
#Teng-0.14_05 package MyDB; use strict; use warnings; use utf8; use DBI; use Teng; use Teng::Schema::Loader; our $TENG; sub teng { $TENG ||= do { my $dbh = DBI->connect("dbi:SQLite:./users.db", '', '', +{ Callbacks => { connected => sub { my $conn = shift; $conn->do(<<EOF); CREATE TABLE user ( id INTEGER PRIMARY KEY, user_name varchar(10), sex varchar(10) default 'male', age INTEGER default 20, ); EOF return; }, }, sqlite_unicode => 1, }); Teng::Schema::Loader->load( dbh => $dbh, namespace => 'MyDB::Schema' ); } } 1; 8
Tengのnew(オブジェクトの作り方)
#Teng-0.14_05 use strict; use warnings; use DBI; use utf8; use Teng; use Teng::Schema::Loader; sub teng { my $dbh = DBI->connect("dbi:SQLite:./users.db", '', '', +{ Callbacks => { connected => sub { my $conn = shift; $conn->do(<<EOF); #テーブルの構造をココに書く CREATE TABLE user ( id INTEGER PRIMARY KEY, user_name varchar(10), sex varchar(10) default 'male', age INTEGER default 20, ); EOF return; }, }, sqlite_unicode => 1,#MySQLは、mysql_enable_utf8 => 1 , }); my $teng = Teng::Schema::Loader->load( dbh => $dbh, namespace => 'MyDB::Schema' ); }
Teng::Schema::Loaderというのを使うと楽
とりあえずメソッド化 永続化
9
SELECT
SQL文の書けるsearch_by_sqlメソッドを使う
use MyDB; my @users = MyDB->teng->search_by_sql( q{#SQL文が普通にかける SELECT id, user_name FROM user WHERE sex = ? AND age > ? }, ['male',20]#bind値は配列のリファレンスで設定 )->all; #Rowオブジェクトなるものがいる for my $row (@users) { #カラムはRowオブジェクトに #カラム名でメソッド呼び出し warn $row->id; warn $row->user_name; }
use MyDB; my $row = MyDB->teng->search_by_sql( q{ SELECT * FROM user WHERE user_name = ? }, ['hirobanex'] )->first;
1行だけの取り出し 複数行の取り出し
10
INSERT、UPDATE、DELETE
SQL文の書けるdoメソッドを使う
use MyDB; MyDB->teng->do(q{ INSERT INTO user ( user_name,sex,age ) VALUES ( ?,?,? ); },undef,('hirobanex','male','26')); # errorハンドリングはTengのほうでやってくれている
INSERT MyDB->teng->do(q{ UPDATE user SET user_name = ? ,age = ? WHERE user_name = ? },undef,('bane','27','hirobanex'));
UPDATE
MyDB->teng->do(q{ DELETE user WHERE user_name = ? },undef,('bane'));
DELETE
hachioji.pm 11
トランザクション
use MyDB; my $teng = MyDB->teng; my $txn = $teng->txn_scope; for my $user_name ('hiro','bane','ytnobody') { $teng->do(q{ INSERT INTO user (user_name) VALUES (?); },umdef,$user_name ); } $txn->commit;
囲うだけ
12
実際のO/Rマッパーの効用
やれること Teng実装
トランザクションをシンプルに書ける DBIx::TransactionManager
突然コネクションが切られることはない $dbh->FETCH('Active'), $dbh->pingの確認
コンストラクション設定を楽にする ×
リファレンスとかでかっこ良く条件文を書く SQL::Maker
インサートしたと同時にその中身とったり、 便利メソッドつくる
Teng::Row(Rowオブジェクト)、 FindOrCreate, BulkInsertなど各種プラグイン
SQL文を発行するタイミングでなんかする inflate,deflate(triggerはない)
SELECTのIN構文になげるバインド値に 配列リファレンスを使いたい
search_namedメソッド
Tengを使いこなしてやれることを広げるためのキーワード
13
その他Tengリファレンス
cpanm Teng 0.14_05
http://perl-users.jp/articles/advent-calendar/2011/teng/
http://search.cpan.org/~nekokak/Teng-0.14_05/
http://walf443.github.com/teng-doc/
最後はソースコードも読もう
14
最後に
YAPC::Asia2012のトークに応募しました!
興味があったら、「いいね!」などお願いしますっ!