前言
SQLite是一個(gè)輕量的屁倔、跨平臺(tái)的卵凑、開源的數(shù)據(jù)庫引擎奈嘿。SQLite每個(gè)數(shù)據(jù)庫都是以單個(gè)文件(.db)的形式存在貌虾,這些數(shù)據(jù)都是以B-Tree的數(shù)據(jù)結(jié)構(gòu)形式存儲(chǔ)在磁盤上。
使用SQLiteDatabase的insert裙犹,delete等方法或者execSQL方法默認(rèn)都開啟了事務(wù)尽狠,如果操作的順利完成才會(huì)更新.db數(shù)據(jù)庫衔憨。事務(wù)的實(shí)現(xiàn)是依賴于名為rollback journal文件,借助這個(gè)臨時(shí)文件來完成原子操作和回滾功能袄膏。
大家可以在/data/data/<packageName>/databases/目錄下看到一個(gè)和數(shù)據(jù)庫同名的.db-journal文件践图。
SQLite是文件級(jí)別的鎖:多個(gè)線程可以同時(shí)讀,但是同時(shí)只能有一個(gè)線程寫沉馆。Android提供了SqliteOpenHelper類码党,加入Java的鎖機(jī)制以便調(diào)用。
模板
public class DbOpenHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "book_provider.db";
public static final String BOOK_TABLE_NAME = "book";
public static final String USER_TALBE_NAME = "user";
private static final int DB_VERSION = 3;
private String CREATE_BOOK_TABLE = "CREATE TABLE IF NOT EXISTS "
+ BOOK_TABLE_NAME + "(_id INTEGER PRIMARY KEY," + "name TEXT)";
private String CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS "
+ USER_TALBE_NAME + "(_id INTEGER PRIMARY KEY," + "name TEXT," + "sex INT)";
public DbOpenHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); }
@Override
public void onCreate(SQLiteDatabase db) { //如果創(chuàng)建了斥黑,就不會(huì)回調(diào)這個(gè)方法揖盘。
db.execSQL(CREATE_BOOK_TABLE);
db.execSQL(CREATE_USER_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO ignored
}
}
線程問題
SQLite的同步鎖精確到數(shù)據(jù)庫級(jí),粒度比較大锌奴,不像別的數(shù)據(jù)庫有表鎖兽狭,行鎖。同一個(gè)時(shí)間只允許一個(gè)連接進(jìn)行寫入操作鹿蜀。
如果多線程同時(shí)讀寫(這里的指不同的線程用使用的是不同的Helper實(shí)例)箕慧,后面的就會(huì)遇到android.database.sqlite.SQLiteException: database is locked這樣的異常。對(duì)于這樣的問題茴恰,解決的辦法就是keep single sqlite connection颠焦,保持單個(gè)SqliteOpenHelper實(shí)例,同時(shí)對(duì)所有數(shù)據(jù)庫操作的方法添加synchronized關(guān)鍵字往枣。
我們常常在多線程中只使用一個(gè)SQLiteDatabase引用蒸健,在用SQLiteDataBase.close()的時(shí)需要注意調(diào)是否還有別的線程在使用這個(gè)實(shí)例。如果一個(gè)線程操作完成后就直接close了婉商,別一個(gè)正在使用這個(gè)數(shù)據(jù)庫的線程就會(huì)異常似忧。所以有些人會(huì)直接把SQLiteDatabase的實(shí)例放在Application中,讓它們的生命周期一致丈秩。也有的做法是寫一個(gè)計(jì)數(shù)器盯捌,當(dāng)計(jì)數(shù)器為0時(shí)才真正關(guān)閉數(shù)據(jù)庫。
使用ORM的問題
目前網(wǎng)上有很多開源的ORM(對(duì)象關(guān)系數(shù)據(jù)映射)框架蘑秽,如greenDAO饺著、ormlite等等。在使用這些框架有必要很了解一下它們的利弊肠牲,特別是一些使用反射的框架幼衰,對(duì)性能的影響會(huì)比較大。有些框架在多線程同步方面也會(huì)產(chǎn)生一些問題缀雳,所以使用時(shí)要有所顧慮渡嚣。
Realm 是最近興起的一個(gè)專注于移動(dòng)設(shè)備數(shù)據(jù)庫的庫,其核心是使用C++編寫,號(hào)稱很多時(shí)候數(shù)據(jù)的存取速度比SQLite要快很多识椰。不過在我的一些項(xiàng)目中绝葡,發(fā)現(xiàn)它讀取并不比SQLite快。