ブログ移行しました
新しいブログは
http://blog.hello-world.jp.net/
になります。
よろしくお願いします。
初めてのYAPC
Perlを始めて2ヶ月が経とうとしています。
昨日はYAPC::Asia Tokyo 2011に参加してきました。
僕がYAPCに行って得たものは
- Perlの世界に触れられたこと
- Perlを用いたサービス運用のTips
- 周りの先輩方の偉大さを改めて実感できたこと
です。
今の自分が恵まれた環境にいることを改めて実感、
そしてその環境を活かしきれていないことを反省しています。
積極性、これが自分に足りていないものだと感じました。
LT後のManaging A Band Of Hackersでは
若い人はコミュニティに参加してほしい
人脈は大事
ということをおっしゃっていました。
これまでコミュニティに参加するのが苦手でしたが、これからはもう少し積極的になろうと思います。
単に人脈を広げるのではなく、人望のある人間を目指して。
ものを作って結果を残す。
watch your logの発表の際に引用されていた
Shut the fuck up and write some code.
この言葉を胸に刻んでおきます。
今はまだperlでの成果物がない状態ですが、来年にはちゃんと結果を残していたい。
言葉足らずの部分が多いですが、YAPCに参加できたことに感謝しています。
Perlのことがもっと好きになれた1日でした。
スピーカーの皆様、スタッフの皆様、スポンサーの皆様、そして参加者の皆様、本当にありがとうございました。
おまけ
スイーツエリアで販売していた『Acme大全2011』をGET!!
「なんかおもしろそう」と、お土産感覚で購入しましたが、第一章は普通にPerl(Perl界隈のことも)の勉強になりました。
なんでもありのAcmeモジュールおもしろい!
「はじめてのPerl」とセットで読むと楽しくPerlを始められると思います。
以下、講演メモ
運用しやすいアプリケーション構築手法
- ログの重要性
- 障害発生時に最初にみる
- ログがないと時間がかかる
- 適切なログに含まれる情報
- 時間
- ログレベル
- ログを見た人に何をしてほしいかが明確になっているように
watch your log
- 必要に応じたエンジニアリングのすすめ
- DevOps
- 障害には監視が必要
- ログ?
- ログの収集方法を紹介
- Komainu
- accesslogの集計
- アプリケーションログの集計
- Komainu
- まとめ
- サービスクオリティの維持
- 問い合わせベースで障害に気付くのは情けない
- 攻めの運用
- Shut the fuck up and write some code.
- コードの良し悪しはとりあえずどうでもいい、結果が全て
- 問題意識を持って行動する
- 密なコミュニケーションを
データの重複登録回避方法は?
perlに限ったことではありませんが、DB処理を行う際、データの重複登録を回避するにはどういう方法をとるのがよいのでしょうか?
WEBアプリケーションの場合、ページリロードによるデータの重複登録が発生することがあり、それをうまく回避する方法はないかと模索中です。
ぱっと思いついたのは、
- データ登録を行う前にチェック用のSQLを実行し、データが存在しなければ登録する方法
- 登録の際に例外処理を行い、意図的に例外を握りつぶす方法
の2通りです。
サンプルとして、id(主キー)とnameを持つmemberテーブルを作ってみます。
テーブル作成
mysql> show create table member\G *************************** 1. row *************************** Table: member Create Table: CREATE TABLE `member` ( `id` bigint(20) NOT NULL, `name` varchar(64) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> desc member; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint(20) | NO | PRI | NULL | | | name | varchar(64) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
1.データ登録の前にチェック用SQLを実行して重複登録を回避する方法
以下は、コマンドラインから引数(idとname)を受け取りデータ登録を行うサンプル
#usr/bin/perl use strict; use warnings; use DBI; use Data::Dumper; my ($id, $name) = @ARGV; die unless (@ARGV == 2); my $dbh = DBI->connect( 'dbi:mysql:dbname=test', 'test_user', 'test', { RaiseError => 1, PrintError => 0, AutoCommit => 0 } ); # データの存在チェック my $sth = $dbh->prepare("SELECT * FROM member WHERE id = ?"); $sth->execute($id); my $data = $sth->fetchrow_hashref; # データが存在しなければ新規登録 if (!$data) { $sth = $dbh->prepare("INSERT INTO member (id, name) VALUES(?, ?)"); $sth->execute($id, $name); $dbh->commit; } $sth = $dbh->prepare("SELECT * FROM member"); $sth->execute(); print Dumper($sth->fetchall_arrayref); $dbh->disconnect;
サンプル実行
新規登録 perl sample.pl 1 test1 $VAR1 = [ [ '1', 'test1' ] ]; 新規登録 perl sample.pl 2 test2 $VAR1 = [ [ '1', 'test1' ], [ '2', 'test2' ] ]; 重複登録 perl sample.pl 1 test1 $VAR1 = [ [ '1', 'test1' ], [ '2', 'test2' ] ];
登録の前にチェック用SQLを実行することで、重複登録が回避できています。
なお、チェックなしにプログラムを実行すると、重複登録になりエラーが発生します。
perl sample.pl 1 test1 DBD::mysql::st execute failed: Duplicate entry '1' for key 'PRIMARY' at exception_sample2.pl line 23. Issuing rollback() due to DESTROY without explicit disconnect() of DBD::mysql::db handle dbname=test at exception_sample.pl line 23.
2.例外処理を使って重複登録を回避する方法
処理内容自体は1.の方法と同じですが、重複登録の回避方法としてevalを用いています。
#usr/bin/perl use strict; use warnings; use DBI; use Data::Dumper; my ($id, $name) = @ARGV; die unless (@ARGV == 2); my $dbh = DBI->connect( 'dbi:mysql:dbname=test', 'test_user', 'test', { RaiseError => 1, PrintError => 0, AutoCommit => 0 } ); my $sth = $dbh->prepare("INSERT INTO member (id, name) VALUES(?, ?)"); eval { # 重複登録の場合、例外発生 $sth->execute($id, $name); $dbh->commit; }; # 何もしない(意図的に例外を握りつぶす) # if ($@) { # # } $sth = $dbh->prepare("SELECT * FROM member"); $sth->execute(); print Dumper($sth->fetchall_arrayref); $dbh->disconnect;
実行結果は1.と同じです。
evalを使って例外処理を行い、意図的に例外を握りつぶすことで、重複登録になってもプログラムは途中終了せず、データの表示が行われます。
自分の中では1.の方法よりも2.の方法のほうがスッキリしていると思うのですが、実際のところどういう方法がいいのか分からず悩んでいます。
他にももっと良い方法があるのでしょうか?
Perlでの例外処理について
Perlで例外処理をしたい場合は、try-catchではなくevalを使うんですね。
(モジュールを使えばtry-catchも使えるそうですが)
初めて見た時、「evalってなんだろう?」と悩んだので残しておきます。
evalでくくって(try)、ifで例外処理(catch)
例外処理のサンプル
#usr/bin/perl use strict; use warnings; eval { die "this is exception"; # 強制的に例外発生 }; if ($@) { print "ERROR:$@"; # 例外内容を表示 }
perlでのswitch文
9/8追記
先輩から、Switchモジュールはバグが多く現在では非推奨モジュールになっているというアドバイスいただきました。
以下、5.12.0ドキュメント(perl5120delta - perldoc.perl.org)より引用
You can silence these deprecation warnings by installing the modules in question from CPAN. To install the latest version of all of them, just install Task::Deprecations::5_12 .Class::ISA
Pod::Plainer
Shell
SwitchSwitch is buggy and should be avoided. You may find Perl's new given/when feature a suitable replacement. See Switch statements in perlsyn for more information.
Switchモジュールを用いたサンプルは残しておきますが、
5.10以降はgivenを用いたほうがいいそうなのでそちらをお使いください。
私の環境では5.8.8だったので、if-else文に置き換えました。
追記終わり
perlではモジュールを利用しないとswitch文が使えないということを知りました
これまで使ってきた言語ではデフォルトでswitch文が使えたのでこれは少し意外でした
switch文を使うにはSwitchモジュールを呼び出す必要があります
以下、case文を使いたいだけの意味のないサンプル
forで回して無理やりswitch文を使ってます
phpでは、caseに該当しないものは「default」で表していましたが、perlのSwitchモジュールでは「else」を用います
サンプルコード
#usr/bin/perl use strict; use warnings; use Switch; for (1..10) { switch ($_) { case 1 { print "hello\n"; } case 2 { print "good\n"; } else { print "this value is $_\n"; } } }
結果
hello good this value is 3 this value is 4 this value is 5 this value is 6 this value is 7 this value is 8 this value is 9 this value is 10
また、perl 5.10以降は標準で組み込まれている「given」を用いることで同様の処理が可能なようですね
givenを用いたサンプルコード
#!usr/bin/perl use strict; use warnings; use 5.10.0; for (1..10) { given ($_) { when (1) { say "hello"; } when (2) { say "good"; } default { say "this value is $_"; } } }
「say "xxx"」を使うことで「print "xxx\n"」の際に必要だった改行コードの省略が可能です
参考にさせていただいたサイト
ベストプラクティスなコーディングを
『Perlベストプラクティス』はまだ読めていないのですが、Perl::Tidyというベストプラクティスなコーディングをサポートしてくれる便利なモジュールがあるとのこと
とりあえず試してみました
- まずはモジュールインストール
cpanm --local-lib=~/perl5 Perl::Tidy
vi ~/.perltidyrc -pbp
- vim用のショートカットを追加
vi ~/.vimrc "選択された部分のソースコードを整形 map ,ptv :! perltidy "ソースコード全体を整形 map ,pt :%! perltidy
これでvimで編集中に
- 「,pt」と入力するとファイル全体を
- vで範囲選択した後に、「,ptv」と入力すると選択範囲を
整形してくれます
これからはベストプラクティスに沿ったコーディングを心がけたいと思います
本もちゃんと読もう
JSONを使ってみる
JSON::XSというモジュールを入れればよさそう
早速、モジュールインストール
cpanm JSON::XS
サンプル
#usr/bin/perl use strict; use warnings; use JSON::XS; use Data::Dumper; # ecode my $json_text = encode_json { scalar => 'text', array => ['data1', 'data2'], hash => { key1 => 'value1', key2 => 'value2' }, complex => ['array1' => { key1 => 'value1', key2 => 'value2' }, 'array2' => { test => 'value'}] }; # decode my $scalar = decode_json $json_text; # dump print Dumper($json_text, $scalar);
実行結果
$VAR1 = '{"hash":{"key2":"value2","key1":"value1"},"array":["data1","data2"],"scalar":"text","complex":["array1",{"key2":"value2","key1":"value1"},"array2",{"test":"value"}]}'; $VAR2 = { 'scalar' => 'text', 'array' => [ 'data1', 'data2' ], 'hash' => { 'key2' => 'value2', 'key1' => 'value1' }, 'complex' => [ 'array1', { 'key2' => 'value2', 'key1' => 'value1' }, 'array2', { 'test' => 'value' } ] };
サンプルデータが適当なので見づらいですが、正しくJSONエンコード/デコードが行えているようです
今日はJSONとDumperの使い方を学びました