「間違った」のではなく正しいことをすべき理由の簡単な例。これは、恐ろしいINSERTパフォーマンスを持つICS4.0.4で実行してテストされました。
まず、列に制約SQLiteOpenHelper
のあるテーブルを作成して、時々競合を引き起こす単純なものです。UNIQUE
class SimpleHelper extends SQLiteOpenHelper {
// InsertHelpers are a really good idea - they format a prepared statement
// for you automatically.
InsertHelper mInsert;
public SimpleHelper(Context context) {
super(context, "tanika.db", null, 1);
}
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
mInsert = new InsertHelper(db, "target");
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE target (\n" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n" +
"val1 TEXT NOT NULL,\n" +
"val2 TEXT NOT NULL,\n" +
"val3 TEXT NOT NULL,\n" +
// Let's make one unique so we can get some juicy conflicts
"val4 TEXT NOT NULL UNIQUE\n" +
")");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
古いものにバンドルされているのでActivity
、次の簡単なテスト方法を追加します。
long test(final int n) {
long started = System.currentTimeMillis();
ContentValues values = new ContentValues();
for (int i = 0; i < n; i++) {
values.clear();
// Every 20th insert, generate a conflict in val4
String val4 = String.valueOf(started + i);
if (i % 20 == 0) {
val4 = "conflict";
}
values.put("val1", "Value1");
values.put("val2", "Value2");
values.put("val3", "Value3");
values.put("val4", val4);
mHelper.mInsert.replace(values);
}
return System.currentTimeMillis() - started;
}
ご覧のとおり、これにより20日ごとに競合が発生しINSERT
ます。呼び出すInsertHelper#replace(..)
と、ヘルパーはINSERT OR REPLACE
on競合を使用します。
それでは、このテストコードを、周囲のトランザクションがある場合とない場合で実行してみましょう。
class Test1 extends AsyncTask<Integer, Void, Long> {
@Override
protected Long doInBackground(Integer... params) {
return test(params[0]);
}
@Override
protected void onPostExecute(Long result) {
System.out.println(getClass().getSimpleName() + " finished in " + result + "ms");
}
}
class Test2 extends AsyncTask<Integer, Void, Long> {
protected Long doInBackground(Integer... params) {
SQLiteDatabase db = mHelper.getWritableDatabase();
db.beginTransaction();
long started = System.currentTimeMillis();
try {
test(params[0]);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return System.currentTimeMillis() - started;
}
@Override
protected void onPostExecute(Long result) {
System.out.println(getClass().getSimpleName() + " finished in " + result + "ms");
}
}
すべてが次のように開始されます。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mHelper = new SimpleHelper(this);
mHelper.getWritableDatabase(); // Forces the helper to initialize.
new Test1().execute(2055);
new Test2().execute(2055);
}
そして結果は?トランザクションがない場合、INSERT
sは41072msかかります。トランザクションでは、940ミリ秒かかります。つまり、FFSは、InsertHelper
sとトランザクションの使用を開始します。