2014年10月24日金曜日

PhalconのDB\AdapterをDIへ登録する際の注意点

今まで勘違いしていたので覚えて置く為のメモ。

PhalconでDIへDb\Adapterを登録してtransactionを一元管理するのはできないのだと思っていたら 使い方が間違っていた。
DIへ登録する時にはshared(共有)として登録すれば呼び出し先で同じコネクションのインスタンス を使用してくれる。逆を言うとsharedしないと同じインスタンスを使用してくれないようだ。
具体的には
// 第三引数にtrueを指定
$di->set('db', function() use ($config) {
    return new \Phalcon\Db\Adapter\Pdo\Postgresql(
    $config->database->toArray());
}, true);
本当にトランザクションが制御できているか以下の方法で確認
DBにテーブルを用意する
CREATE TABLE name1 (
  id SERIAL PRIMARY KEY,
  name text
);
テスト登録用処理を実装したモデルクラスを用意する。
class Name1 extends \Phalcon\MVC\Model
{

    public $id;
    public $name;

    public function getSource()
    {
        return "name1";
    }

    /**
      * 引数のコネクションと関数内で生成したコネクション
      * でそれぞれ登録
      *
      */
    public static function insertTest($src_db){
        $name = new \App\Mvc\Model\Name1();
        $db = $name->getDI()->get("db");
        for($i=0;$i<5;$i++){
            $name = new \App\Mvc\Model\Name1();
            $name->name = 'FFFFF' . sprintf("%05d", $i);
            $name->create();
            $result = $db->query("INSERT INTO name1(name) VALUES(
                '" . "DDDDD" . sprintf("%05d", $i) . "')");
            $resulta = $src_db->query("INSERT INTO name1(name) VALUES(
                '" . "EEEEE" . sprintf("%05d", $i) . "')");

        }
    }
}
DIのsharedをtrueにしたものとしないものの両方で以下の処理を実行する。
具体的にはコントローラー、生成したモデルのテスト用関数で登録処理が行われ、例外を意図的に 発生させてrollbackを行う。
try{
   
    $this->db->begin();
    for($i=0;$i<5;$i++){
        $name = new \App\Mvc\Model\Name1();
        $name->name = 'AAAAAA' . sprintf("%05d", $i);
        $name->create();
                
        $result = $this->db->query("INSERT INTO name1(name) VALUES(
            '" . "BBBBB" . sprintf("%05d", $i) . "')");
    }
    \App\Mvc\Model\Name1::insertTest($this->db);
            
    throw new \Exception("trnsaction test");
    $this->db->commit();
}catch(Exception $e){
    if($this->db->isUnderTransaction()){
        $this->db->rollback();
    }
    throw $e;
}

sharedした場合の結果は
test=# select * from name1;
 id | name 
----+------
(0 行)

しなかった場合、インスタンスを別で取得して登録した分が残ってしまう。
test=# select * from name1;
 id |    name    
----+------------
 12 | DDDDD00000
 15 | DDDDD00001
 18 | DDDDD00002
 21 | DDDDD00003
 24 | DDDDD00004
(5 行)
一元管理したい場合はsharedをする事で可能になる。一番起きそうなのは一元管理するつもりだったのに sharedしないで登録してしまいtransactionがめちゃくちゃになってしまったという事故。

connectionのインスタンスはDB回りのクラスで管理されるものと思い込んでいたのでDIでやる発想が無かった。 こんな方法もあるんだな。

2014年10月14日火曜日

Google Play アプリ開発で参考にした本

Google Play版のPocket Trumpetterも無事リリースに至りました。

アプリ開発ではもはや名著「初めてのAndroid 第3版」を参考にしています。

初めてのAndroid 第3版

javaの基本的な知識は必要ですが、シンプルなアプリの開発ならこの本の例を作る過程で身につく
と思います(少なくとも私は身についたと思っています)。
強いて惜しいと思われるのは、内容はちょっと古いんじゃないかと思っています。
サンプルで使用されたライブラリや関数が非推奨になっていたり、Fragmentについては触れられなか
ったりと。まぁこんなものは大したマイナスではないと思いますが。