当前位置: 代码迷 >> 综合 >> SQLiteOpenHelper onCreate()/ onUpgrade()何时运行?
  详细解决方案

SQLiteOpenHelper onCreate()/ onUpgrade()何时运行?

热度:60   发布时间:2024-02-12 11:05:43.0

本文翻译自:When is SQLiteOpenHelper onCreate() / onUpgrade() run?

I have created my tables in my SQLiteOpenHelper onCreate() but receive 我已经在SQLiteOpenHelper onCreate()创建了表,但收到了

SQLiteException: no such table

or 要么

SQLiteException: no such column

errors. 错误。 Why? 为什么?

NOTE: 注意:

(This is the amalgamated summary of tens of similar questions every week. Attempting to provide a "canonical" community wiki question/answer here so that all those questions can be directed to a good reference.) (这是每周数十个类似问题的汇总摘要。尝试在此处提供“规范”社区Wiki问题/答案,以便将所有这些问题都可以作为参考。)


#1楼

参考:https://stackoom.com/question/1tOvm/SQLiteOpenHelper-onCreate-onUpgrade-何时运行


#2楼

SQLiteOpenHelper onCreate() and onUpgrade() callbacks are invoked when the database is actually opened, for example by a call to getWritableDatabase() . 实际打开数据库时,将调用SQLiteOpenHelper onCreate()onUpgrade()回调,例如,通过调用getWritableDatabase() The database is not opened when the database helper object itself is created. 创建数据库助手对象本身时,不会打开数据库。

SQLiteOpenHelper versions the database files. SQLiteOpenHelper对数据库文件进行版本控制。 The version number is the int argument passed to the constructor . 版本号是传递给构造函数的int参数。 In the database file, the version number is stored in PRAGMA user_version . 在数据库文件中,版本号存储在PRAGMA user_version

onCreate() is only run when the database file did not exist and was just created. 仅当数据库文件不存在且刚创建时才运行onCreate() If onCreate() returns successfully (doesn't throw an exception), the database is assumed to be created with the requested version number. 如果onCreate()成功返回(不引发异常),则假定使用请求的版本号创建数据库。 As an implication, you should not catch SQLException s in onCreate() yourself. 这意味着,您不应该自己在onCreate()捕获SQLException

onUpgrade() is only called when the database file exists but the stored version number is lower than requested in constructor. 仅当数据库文件存在但存储的版本号低于构造函数中的请求时,才调用onUpgrade() The onUpgrade() should update the table schema to the requested version. onUpgrade()应该将表架构更新为请求的版本。

When changing the table schema in code ( onCreate() ), you should make sure the database is updated. 在代码( onCreate() )中更改表架构时,应确保数据库已更新。 Two main approaches: 两种主要方法:

  1. Delete the old database file so that onCreate() is run again. 删除旧的数据库文件,以便再次运行onCreate() This is often preferred at development time where you have control over the installed versions and data loss is not an issue. 在您可以控制安装的版本并且数据丢失不是问题的开发时间,这通常是首选。 Some ways to to delete the database file: 删除数据库文件的一些方法:

    • Uninstall the application. 卸载应用程序。 Use the application manager or adb uninstall your.package.name from shell. 使用应用程序管理器或adb uninstall your.package.name从shell adb uninstall your.package.name

    • Clear application data. 清除应用程序数据。 Use the application manager. 使用应用程序管理器。

  2. Increment the database version so that onUpgrade() is invoked. 递增数据库版本,以便调用onUpgrade() This is slightly more complicated as more code is needed. 随着需要更多代码,这会稍微复杂一些。

    • For development time schema upgrades where data loss is not an issue, you can just use execSQL("DROP TABLE IF EXISTS <tablename>") in to remove your existing tables and call onCreate() to recreate the database. 对于没有数据丢失问题的开发时架构升级,您可以仅使用execSQL("DROP TABLE IF EXISTS <tablename>")来删除现有表,然后调用onCreate()重新创建数据库。

    • For released versions, you should implement data migration in onUpgrade() so your users don't lose their data. 对于已发布的版本,应在onUpgrade()实现数据迁移,以使用户不会丢失其数据。


#3楼

To further add missing points here, as per the request by Jaskey 根据Jaskey的要求,在此处进一步添加缺失点

Database version is stored within the SQLite database file. 数据库版本存储在SQLite数据库文件中。

catch is the constructor catch是构造函数

SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

So when the database helper constructor is called with a name (2nd param), platform checks if the database exists or not and if the database exists, it gets the version information from the database file header and triggers the right call back 因此,当使用name (第二个参数)调用数据库帮助程序构造函数时,平台会检查数据库是否存在以及数据库是否存在,它将从数据库文件头获取版本信息并触发正确的回调

As already explained in the older answer, if the database with the name doesn't exists, it triggers onCreate . 如较早的答案中已经解释的,如果名称不存在的数据库将触发onCreate

Below explanation explains onUpgrade case with an example. 下面的解释以一个例子说明onUpgrade情况。

Say, your first version of application had the DatabaseHelper (extending SQLiteOpenHelper ) with constructor passing version as 1 and then you provided an upgraded application with the new source code having version passed as 2 , then automatically when the DatabaseHelper is constructed, platform triggers onUpgrade by seeing the file already exists, but the version is lower than the current version which you have passed. 假设您的第一个应用程序版本的DatabaseHelper (扩展了SQLiteOpenHelper )的构造函数将版本传递为1 ,然后您为升级后的应用程序提供了新的源代码,其版本传递为2 ,然后在构造DatabaseHelper时自动触发了平台的onUpgrade触发看到文件已经存在,但是版本低于您通过的当前版本。

Now say you are planing to give a third version of application with db version as 3 (db version is increased only when database schema is to be modified). 现在说您打算提供数据库版本为3的应用程序的第三版本(仅当要修改数据库架构时才增加数据库版本)。 In such incremental upgrades, you have to write the upgrade logic from each version incrementally for a better maintainable code 在这种增量升级中,您必须逐个增量地编写每个版本的升级逻辑,以便获得更好的可维护代码

Example pseudo code below: 下面的示例伪代码:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {switch(oldVersion) {case 1://upgrade logic from version 1 to 2case 2://upgrade logic from version 2 to 3case 3://upgrade logic from version 3 to 4break;default:throw new IllegalStateException("onUpgrade() with unknown oldVersion " + oldVersion);}
}

Notice the missing break statement in case 1 and 2 . 注意情况12缺少的break语句。 This is what I mean by incremental upgrade. 这就是我所说的增量升级。

Say if the old version is 2 and new version is 4 , then the logic will upgrade the database from 2 to 3 and then to 4 假设旧版本是2 ,新版本是4 ,则逻辑会将数据库从2升级到3 ,然后再升级到4

If old version is 3 and new version is 4 , it will just run the upgrade logic for 3 to 4 如果旧版本是3 ,新版本是4 ,它将只运行34的升级逻辑


#4楼

onCreate()

  1. When we create DataBase at a first time (ie Database is not exists) onCreate() create database with version which is passed in SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) 当我们第一次创建数据库(即数据库不存在)时, onCreate()创建具有在SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)传递的版本的数据库SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate() method is creating the tables you've defined and executing any other code you've written. onCreate()方法将创建您已定义的表并执行您编写的任何其他代码。 However, this method will only be called if the SQLite file is missing in your app's data directory ( /data/data/your.apps.classpath/databases ). 但是,仅当应用程序的数据目录( /data/data/your.apps.classpath/databases )中缺少SQLite文件时,才会调用此方法。

  3. This method will not be called if you've changed your code and relaunched in the emulator. 如果您更改了代码并在模拟器中重新启动,则不会调用此方法。 If you want onCreate() to run you need to use adb to delete the SQLite database file. 如果要运行onCreate() ,则需要使用adb删除SQLite数据库文件。

onUpgrade()

  1. SQLiteOpenHelper should call the super constructor. SQLiteOpenHelper应该调用超级构造函数。
  2. The onUpgrade() method will only be called when the version integer is larger than the current version running in the app. 仅当版本整数大于应用程序中运行的当前版本时,才会调用onUpgrade()方法。
  3. If you want the onUpgrade() method to be called, you need to increment the version number in your code. 如果要调用onUpgrade()方法,则需要增加代码中的版本号。

#5楼

Uninstall your application from the emulator or device. 从仿真器或设备上卸载应用程序。 Run the app again. 再次运行该应用程序。 (OnCreate() is not executed when the database already exists) (当数据库已经存在时,不执行OnCreate())


#6楼

Points to remember when extending SQLiteOpenHelper 扩展SQLiteOpenHelper时要记住的SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); - This should be invoked first line of constructor -应该在构造函数的第一行调用
  2. override onCreate and onUpgrade (if needed) 覆盖onCreateonUpgrade (如果需要)
  3. onCreate will be invoked only when getWritableDatabase() or getReadableDatabase() is executed. 仅当执行getWritableDatabase()getReadableDatabase()时,才会调用onCreate And this will only invoked once when a DBName specified in the first step is not available. 并且仅在第一步中指定的DBName不可用时才调用一次。 You can add create table query on onCreate method 您可以在onCreate方法上添加创建表查询
  4. Whenever you want to add new table just change DBversion and do the queries in onUpgrade table or simply uninstall then install the app. 每当您要添加新表时,只需更改DBversion并在onUpgrade表中进行查询,或者简单地卸载然后安装该应用程序即可。