構造函數簽名
public DatabaseHelper(Context context, String name, CursorFactory factory, int version)
version 參數規則
| 規則 | 說明 |
| 類型 | int(32位有符號整數) |
| 取值範圍 | 1 ~ 2,147,483,647(建議從 1 開始) |
| 遞增原則 | 嚴格單調遞增,每次 Schema 變更 +1 |
| 可否跳號 | 可(如 1→3),但無實際意義,不推薦 |
| 可否減小 | 絕對不可,會導致數據丟失或崩潰 |
版本變更觸發機制
// 內部邏輯簡化
if (newVersion > oldVersion) {
onUpgrade(db, oldVersion, newVersion); // 必須實現遷移邏輯
} else if (newVersion < oldVersion) {
onDowngrade(db, oldVersion, newVersion); // 罕見,通常拋異常
}
// 相等則無操作
最佳實踐模式
1. 定義常量而非硬編碼
private static final int DATABASE_VERSION = 7; // 當前版本
private static final String DATABASE_NAME = "app.db";
2. onUpgrade 實現增量遷移
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 逐版本遷移,確保從任意舊版本都能升級到最新
if (oldVersion < 2) {
db.execSQL("ALTER TABLE users ADD COLUMN phone TEXT");
}
if (oldVersion < 3) {
db.execSQL("CREATE INDEX idx_email ON users(email)");
}
if (oldVersion < 5) {
// 版本 4 跳過也無妨,邏輯由 <5 覆蓋
db.execSQL("CREATE TABLE logs (...)");
}
// ... 後續版本
}
3. 開發期重置數據庫技巧
// 僅調試構建時允許清數據重建
@Override
public void onCreate(SQLiteDatabase db) {
if (BuildConfig.DEBUG) {
db.execSQL("DROP TABLE IF EXISTS users");
}
// 正常建表
}
常見錯誤與後果
| 錯誤操作 | 後果 |
| 版本號不變但修改了建表 SQL | onCreate 不執行,新用戶建表舊結構,舊用戶無變化 → 崩潰/數據不一致 |
| 版本號倒退(如 3→2) | 觸發 onDowngrade,默認拋異常;若未重寫則崩潰 |
| onUpgrade 中執行耗時操作/網絡請求 | ANR 風險,應在異步線程預處理,升級只執行 DDL |
| 多設備同步時版本衝突 | 需引入遷移腳本版本管理(如 Room 的 Migration) |
進階:Room 資料庫的版本管理
現代 Android 開發推薦使用 Room,提供編譯期驗證的遷移機制:
@Database(entities = {User.class}, version = 7, exportSchema = true)
public abstract class AppDatabase extends RoomDatabase {
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE users ADD COLUMN phone TEXT");
}
};
// 註冊所有遷移
}