【问题标题】:Why is onUpgrade() not being invoked on Android sqlite database?为什么在 Android sqlite 数据库上没有调用 onUpgrade()?
【发布时间】:2011-10-04 12:00:04
【问题描述】:

我想在我的安卓模拟器上安装我的数据库时升级它。 我已将继承自 SQLiteOpenHelper 的 DbHelper 中的 db 版本设置为 +1。

但是,当我的第一个活动加载时,我实例化了我的 DbHelper,我希望 SQLiteOpenHelper 调用 onUpgrade,因为 db 版本现在更新了。但是它永远不会被调用。我想知道我是否缺少某些东西。 DbHelper 用于与新版本进行比较的版本存储在哪里?为什么这不起作用?

我实际上是将数据库从资产文件夹复制到数据文件夹中,而不是重新创建架构。

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 );
    }


}

【问题讨论】:

  • 如果您显示用于递增数据库版本的代码,那就太好了。
  • 增加数据库版本?我以为 android 会为你处理这个。
  • db版本如何递增?
  • @jaffa 在 sqlite 中,每个数据库都有一个 PRAGMA user_version。 android 将此值与您提供给 SQLiteOpenHelper 的构造函数的值进行比较。如果它找到您的版本 > user_version,它会调用 onUpgrade() 并将 PRAGMA user_version 设置为新值,否则它会调用 onCreate()。所以你所要做的就是增加你提供给 SQLiteOpenHelper 构造函数的版本并实现 onUpgrade() 方法来修改数据库到所需的新状态。

标签: android sqlite


【解决方案1】:

这是来自SQLiteOpenHelper.getWritableDatabase()的代码sn-p:

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 的实例,就必须使用这些调用。您不应该使用自己的方法,除非它们是 getWritableDatabasegetReadableDatabase 方法的包装器。

【讨论】:

  • 这是否意味着每次用户调用getWritableDatabase()时都会调用onUpgrade()
  • 是的,如果它发现它拥有的版本高于当前/以前的版本。
  • 节省时间!当我不得不触发数据库更新时,只需使用上述方法获取一个 WRITEABLEDATABASE 即可。
  • 我现在正在查看的版本调用此代码,而与“可写”参数无关。因此,每当您检索数据库实例时,都会执行 onCreate、onUpgrade 和 onDowngrade 方法,具体取决于当前数据库版本。要触发此操作,您不必调用 getWritableDatabase(),但也可以调用 getReadableDatabase()。
  • @AlenSiljak 是正确的。我只是想给出一个简单的、不混淆的答案。我会更新答案。
【解决方案2】:

Documentation 说:

在调用 getWritableDatabase() 或 getReadableDatabase() 之一之前,不会实际创建或打开数据库。

我看到您已经实现了自己的获取数据库的方法:openDataBaseForRead()openDataBaseForWrite()。这很糟糕;-)

【讨论】:

  • 为什么不好?我想我将它们用于测试目的。
  • 这很棒。当我启动它时,我的应用程序曾经 onUpgrade,但显然我的启动器不再有任何数据库调用,所以我正在努力弄清楚为什么它没有升级 - 必须导航到 did 调用数据库!
【解决方案3】:

我已经找到了问题所在。 仅当您从资产中复制数据库时才会出现此问题。 assets 文件夹中的 db 有一个默认版本 0。因此,当您使用版本号(例如 1)调用数据库打开助手,然后用 assets 中的那个覆盖它时,版本号将重置为 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 类的超级方法(你的数据库管理器的构造函数)之前更新数据库版本。

`

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:我知道答案很晚,但它可能对像我这样正在寻找这个特定解决方案的人有所帮助

【讨论】:

  • 聪明的主意。我的情况与此相同,这对我很有帮助。干杯
  • 您可以通过从 OnCreate 调用 onUpgrad 并处理 onUpgrade 中的所有内容来更轻松地归档它,您也可以根据文档调用 OnConfigure 中的编译指示此方法应该只调用配置参数的方法...或执行 PRAGMA 语句
【解决方案4】:

在我的情况下资产文件夹中的数据库版本和代码中的当前数据库版本,两者都是相同的,后来我在代码中增加了当前数据库版本,然后调用了onUpgrade方法。

【讨论】:

    猜你喜欢
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多