SQLiteのポイント
DBHelperはSingletonで
SQLiteOpenHelperを継承したDatabaseHelperというクラスを作成しました。このDatabaseHelperはSingletonが良さそうです。
毎回、new DatabaseHelper(context)を返していたところ、複数スレッドからのDBアクセスでエラー(DBファイルのlock)が出てしまいました。複数スレッドで別のインスタンスを扱っていたのが原因のようでした。ご注意を。
[java]
public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper instance = null;
private static final String DATABASE_NAME = “AnniversaryDB”;
private static final int DATABASE_VERSION = 1;
private DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public static DatabaseHelper getInstance(Context context) {
if (instance == null) {
instance = new DatabaseHelper(context);
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase db) {
// create table
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// drop table
// create table
}
}
[/java]
このSingletonは手抜き工事ですが、サンプルですので。呼び出し側のソースは、次のトランザクションの項目で出てきます。
トランザクション
トランザクションをかけるのを忘れずに。読み込みの時は、getReadableDatabase()で読み込み専用のインスタンスを取得できます。「closeは明示的にしなくても良い」と書いてあるブログ(ここ)を発見したのですが、closeしないとエラーで怒られました。どっちが良いのでしょうか・・? サンプルはcloseしていないので、closeしない方がよいのかもしれません。
[java]
@Override
public Profile getProfile(Context context, long id) {
DatabaseHelper dbHelper = DatabaseHelper.getInstance(context);
SQLiteDatabase db = dbHelper.getReadableDatabase();
Profile profile = null;
try {
db.beginTransaction();
ProfileDao profileDao = DaoFactory.getProfileDao(db);
profile = profileDao.findById(id);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
db.close();
}
return profile;
}
[/java]
Cusorを閉じる
queryを発行して返されたCusorをループで回しますが、回し終わったらcloseしましょう。これもエラーで怒られました。
[java]
@Override
public List
List
Cursor cursor = db.query(TABLE_NAME, COLUMNS, null, null,
null, null, COLUMN_ID);
while (cursor.moveToNext()) {
Profile profile = new Profile();
profile.setId(cursor.getInt(COLUMN_ID_INDEX));
profileList.add(profile);
}
cursor.close();
return profileList;
}
[/java]
高速化
SQLiteStatementを事前にコンパイルして、発行した方が早いです。
[java]
// insert statement
private static SQLiteStatement insertStatement;
private static final String insertSql = “insert into " + TABLE_NAME + " values(null, ?, ?);”;
public void setDb(SQLiteDatabase db) {
this.db = db;
insertStatement = db.compileStatement(insertSql);
}
@Override
public long insert(Anniversary anniversary) {
insertStatement.bindLong(COLUMN_PROFILEID_INDEX, anniversary.getProfileId());
insertStatement.bindLong(COLUMN_TYPE_INDEX, anniversary.getType());
return insertStatement.executeInsert();
}
[/java]