連載
» 2012年09月21日 10時00分 UPDATE

Android Tips(20):知っておきたいSQLiteデータベースの注意点 (1/2)

Androidアプリ開発者のためのTips集。「SQLite」を使用する上で気を付けなくてはならない幾つかのポイントを解説する。加えて、前回のTipsで紹介し切れなかったデータベースのバージョンアップ処理についても紹介する。

[秋本耕平(イーフロー),@IT MONOist]
Android Tips

Tips概要と動作検証環境

用途 基本
カテゴリ データ処理
レベル 初級
動作確認環境 Android 2.3.3(GingerBread) エミュレータにて動作確認
備考 今回のTipsは上記環境で動作確認・検証を行っています


Tips 20:知っておきたいSQLiteデータベースの注意点

 前回のTipsでは、Androidで「SQLite」データベースを使用する基本的な方法を紹介した。

 今回は、実際にデータベースアプリケーションを開発する上で、気を付けなくてはならない幾つかのポイントを解説するとともに、前回のTipsで紹介し切れなかったデータベースのバージョンアップ処理についても紹介する。

テーブル定義についての注意点

 Androidでデータベースアプリケーションを開発する際の注意点は3つある。

 最初の注意点は、テーブルの定義に関するものだ。

 テーブルの定義に使用するSQLは、SQLiteの構文をそのまま利用できる。しかし、利用に当たり、1点だけ“Android独自の作法”が存在する。それは「テーブルに『_id』というカラムを定義する」というものだ。

 前回のTipsで紹介したサンプルコードでも、名前格納用の「name」カラム、年齢格納用の「age」カラムの他に、プライマリキーとして「_id」という名前のカラムを定義した。

        /**
         * このデータベースを初めて使用する時に実行される処理
         * テーブルの作成や初期データの投入を行う
         */
        @Override
        public void onCreate( SQLiteDatabase db ) {
            // テーブルを作成。SQLの文法は通常のSQLiteと同様
            db.execSQL(
                    "create table name_book_table ("
                    + "_id  integer primary key autoincrement not null, "
                    + "name text not null, "
                    + "age  integer )" );
            // 必要なら、ここで他のテーブルを作成したり、初期データを挿入したりする
        }

 なぜ、このような作法が必要なのか。それは、Androidの一部のクラスが「_id」という名前のユニークキーの存在を前提に作られているためだ。例えば、Androidの画面部品の中に、データベースの検索結果を表示しやすくするための仕組みが備わっているものがある。実は、こういった仕組みの中で「_id」という名前のカラムが利用されているのだ。そのため、“必須”というわけではないのだが、Androidならではの作法として、特に理由がない限り、「_id」というカラムを定義するのが定石になっている。

パターン検索についての注意点

 2つ目の注意点は、検索に関するものだ。

 SQLで部分一致の検索を行う際は、Like演算子とワイルドカード文字「%」を使用する。Androidでもこの文法を使えるのだが、以下のように記述してしまうと正常に動作しない。

        // name_book_table から、
        // name カラムが部分一致するものを検索する
        cursor = db.query( "name_book_table", 
                new String[]{ "name", "age" }, 
                "name like %?%", 
                new String[]{ "太郎" }, 
                    null, null, null );

 正しく動作する記述を以下に示す。

        // name_book_table から、
        // name カラムが部分一致するものを検索する
        cursor = db.query( "name_book_table", 
                new String[]{ "name", "age" }, 
                "name like ?", 
                new String[]{ "%太郎%" }, 
                    null, null, null );

 ポイントは、ワイルドカード文字を第3引数ではなく、第4引数に入れるということだ。知っていればどうということもないTipsだが、もともとのSQLが簡単なだけに、ハマッてしまうと、なかなか修正方法に気が付かないことが多い。

データベースのクローズについての注意点

 3つ目の注意点は、データベースのクローズについてだ。

 “使い終わったSQLiteDatabaseオブジェクトはクローズする”のが基本的な考え方である。ただ、実際にclose()メソッドが用意されているにもかかわらず、明示的なclose()呼び出しを行わないように実装するケースが多々ある。

 その理由を説明する前に、前回のTipsをおさらいしよう。

 データベースの操作に使用するSQLiteDatabaseオブジェクトを取得するには、SQLiteOpenHelperのサブクラスを使用するのが一般的である。

        // Helperを使用してDBを開く
        NameBookDBHelper dbHelper = new NameBookDBHelper( context );
        SQLiteDatabase db = dbHelper.getWritableDatabase();
※NameBookDBHelperは、前回のサンプルコードで作成したSQLiteOpenHelperのサブクラス

 実は、SQLiteDatabaseの明示的なclose()を行わない理由は、このSQLiteOpenHelperにある。SQLiteOpenHelperは、内部にSQLiteDatabaseオブジェクトを保存しており、getWritableDatabase()で返すSQLiteDatabaseオブジェクトは毎回同一のものとなる。

 つまり、SQLiteDatabaseのclose()を実行してしまうと、次回以降に同じSQLiteOpenHelperを使ってデータベースを開いたときに、既にclose()された状態のオブジェクトが返されてしまうのだ。そのような事情から、アプリケーション終了時などの明白なタイミング以外は、SQLiteDatabaseをclose()しないように実装する場合が多い。

※ただし、SQLiteDatabaseのfinalize()メソッドの中で、close()メソッドが呼ばれるので、明示的な呼び出しがなくとも一応クローズは行われる。


       1|2 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.