ビギナーだから使いたいO/Rマッパー ~Tengを使った開発

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