我希望在将数据库安装到我的Android模拟器上时对其进行升级。 我在我的DbHelper中设置了db版本,它继承自SQLiteOpenHelper到+1。
然而,当我的第一个活动加载时,我实例化我的DbHelper,我希望SQLiteOpenHelper调用onUpgrade,因为db版本现在更新了。但它永远不会被称为。我想知道是否有我遗失的东西。 DbHelper使用的版本在哪里存储以与新版本进行比较?为什么这不起作用?
我实际上是将数据库从assets文件夹复制到数据文件夹,而不是重新创建架构。
public class DbHelper extends SQLiteOpenHelper {
private static final String TAG = "DbHelper";
static final String DB_NAME = "caddata.sqlite";
static final int DB_VERSION = 4;
private static String DB_PATH = "";
private Context myContext;
private SQLiteDatabase myDataBase;
public DbHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.myContext = context;
DB_PATH = "/data/data/"
+ context.getApplicationContext().getPackageName()
+ "/databases/";
}
public DbHelper open() throws SQLException {
myDataBase = getWritableDatabase();
Log.d(TAG, "DbHelper Opening Version: " + this.myDataBase.getVersion());
return this;
}
@Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.d(TAG, "onCreate called");
try {
createDataBase();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if ( newVersion > oldVersion)
{
Log.d(TAG, "New database version exists for upgrade.");
try {
Log.d(TAG, "Copying database...");
copyDataBase();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (!dbExist) {
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
openDataBaseForRead();
}
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READONLY
| SQLiteDatabase.NO_LOCALIZED_COLLATORS);
Log.d(TAG, "db exists");
} catch (SQLiteException e) {
// database does't exist yet.
Log.d(TAG, "db doesn't exist");
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
private void copyDataBase() throws IOException {
// Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
// transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[2048];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
myDataBase.setVersion(DB_VERSION);
}
public void openDataBaseForRead() throws SQLException {
// Open the database
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}
public void openDataBaseForWrite() throws SQLException {
// Open the database
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.NO_LOCALIZED_COLLATORS );
}
}
答案 0 :(得分:28)
这是SQLiteOpenHelper.getWritableDatabase()
来源的代码段:
int version = db.getVersion();
if (version != mNewVersion) {
db.beginTransaction();
try {
if (version == 0) {
onCreate(db);
} else {
if (version > mNewVersion) {
onDowngrade(db, version, mNewVersion);
} else {
onUpgrade(db, version, mNewVersion);
}
}
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
onOpen(db);
如您所见,onCreate()
或onUpgrade()
在getWritableDatabase()
的调用中被调用。
只要您需要SQLiteDatabase
的实例,就必须使用这些调用。您不应该使用自己的方法,除非它们是getWritableDatabase
或getReadableDatabase
方法的包装。
答案 1 :(得分:12)
在调用getWritableDatabase()或getReadableDatabase()之一之前,实际上并未创建或打开数据库。
我发现您已经实现了自己的获取数据库的方法:openDataBaseForRead()
和openDataBaseForWrite()
。那很糟糕; - )
答案 2 :(得分:3)
我已经找到了问题所在。 只有从资产中复制数据库时才会出现此问题。 assets文件夹中的db具有默认版本0.因此,当您使用版本号(例如1)调用数据库打开帮助程序,然后使用资产中的一个覆盖它时,版本号将重置为0.
当您调用应该调用onUpgrade方法的db.getReadableDatabase()或db.getWriteableDatabase时,它会失败,因为版本号0应该是一个新数据库。你可以查看SqliteOpenHelper的源代码。 仅当版本大于零且当前版本大于旧版本时,它才会触发onUpgrade方法。
`
db.beginTransaction();
try {
//Skips updating in your case
if (version == 0) {
onCreate(db);
} else {
if (version > mNewVersion) {
onDowngrade(db, version, mNewVersion);
} else {
onUpgrade(db, version, mNewVersion);
}
}
db.setVersion(mNewVersion);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
`
所以这就是我为克服这个问题所做的。它没有完美的解决方案,但它的工作原理。基本上,在调用SQLiteOpenHelper类的超级方法(数据库管理器的构造函数)之前,需要更新db版本。
`
try
{
String myPath = MyApplication.context.getDatabasePath(DATABASE_NAME).toString();
//open a database directly without Sqliteopenhelper
SQLiteDatabase myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
//if the version is default 0 the update the version
if (myDataBase.getVersion() == 0)
{
//update the database version to the previous one
myDataBase.execSQL("PRAGMA user_version = " + 1);
}
//Close DataBase
myDataBase.close();
}
catch (Exception e)
{
//Do Nothing a fresh install happened
}
`
P.S:我知道答案很晚,但对于像我这样寻找这种特殊解决方案的人来说,这可能会有所帮助答案 3 :(得分:0)
在我的情况下,资产文件夹中的数据库版本和代码中的当前数据库版本相同,后来我增加了代码中的当前数据库版本,然后调用了onUpgrade方法。