什么时候SQLiteOpenHelper的onCreate()/ onUpgrade()运行?

我在我的SQLiteOpenHelper onCreate()创build我的表,但收到

 SQLiteException: no such table 

要么

 SQLiteException: no such column 

错误。 为什么?

注意:

(这是每周几十个类似问题的汇总总结,试图在这里提供一个“规范的”社区wiki问题/答案,以便所有这些问题都可以被引导到一个很好的参考)。

实际打开数据库时调用SQLiteOpenHelper onCreate()onUpgrade()callback,例如调用getWritableDatabase() 。 创build数据库帮助程序对象时,数据库不会打开。

SQLiteOpenHelper版本的数据库文件。 版本号是传递给构造函数的int参数。 在数据库文件中,版本号存储在PRAGMA user_version

onCreate()只在数据库文件不存在并刚刚创build时才运行。 如果onCreate()成功返回(不抛出exception),则假定数据库使用所请求的版本号创build。 作为暗示,您不应该在onCreate()捕获SQLException

onUpgrade()只在数据库文件存在时才被调用,但存储的版本号低于构造函数中的要求。 onUpgrade()应该将表模式更新为所请求的版本。

在代码( onCreate() )中更改表架构时,应确保数据库已更新。 两个主要方法:

  1. 删除旧的数据库文件,以便再次运行onCreate() 。 在开发时,这通常是首选,您可以控制安装的版本,数据丢失不是问题。 一些方法来删除数据库文件:

    • 卸载应用程序。 使用应用程序pipe理器或adb uninstall your.package.name从shell中adb uninstall your.package.name

    • 清除应用程序数据 使用应用程序pipe理器。

  2. 增加数据库版本,以便调用onUpgrade() 。 随着需要更多的代码,这会稍微复杂一些。

    • 对于数据丢失不是问题的开发时间模式升级,可以使用execSQL("DROP TABLE IF EXISTS <tablename>")来删除现有表并调用onCreate()来重新创build数据库。

    • 对于发布的版本,您应该在onUpgrade()实现数据迁移,以便您的用户不会丢失数据。

根据Jaskey的要求,在这里进一步增加缺失点

数据库版本存储在SQLite数据库文件中。

catch是构造函数

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

因此,当数据库帮助器构造函数被调用name (第二参数)时,平台会检查数据库是否存在,如果数据库存在,它将从数据库文件头获取版本信息并触发正确的callback

正如前面已经解释过的,如果名称不存在的数据库,它会触发onCreate

下面以一个例子来说明onUpgrade情况。

假设你的第一个版本的应用程序有DatabaseHelper (扩展SQLiteOpenHelper ),其构造函数传递版本为1 ,然后你提供了一个升级的应用程序,新的源代码的版本传递为2 ,然后当DatabaseHelper被构造时,平台自动触发onUpgrade看到文件已经存在,但版本低于您已经传递的当前版本。

现在说你打算给数据库版本为3的应用程序的第三个版本(db版本是只有当数据库架构将被修改)。 在这种增量升级中,您必须逐渐从每个版本编写升级逻辑,以获得更好的可维护代码

下面的例子伪代码:

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

注意情况12的缺失break声明。 这就是我所说的增量升级。

说如果旧版本是2 ,新版本是4 ,那么逻辑将数据库从2升级到3 ,然后升级到4

如果旧版本为3 ,新版本为4 ,则只运行升级逻辑34

onCreate()

  1. 当我们第一次创build数据库(即数据库不存在) onCreate()创build数据库与SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)传递的SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()方法创build您定义的表并执行您编写的任何其他代码。 但是,只有在应用程序数据目录中缺lessSQLite文件( /data/data/your.apps.classpath/databases )时才会调用此方法。

  3. 如果您更改了代码并在模拟器中重新启动,则不会调用此方法。 如果你想运行onCreate() ,你需要使用adb来删除SQLite数据库文件。

onUpgrade()

  1. SQLiteOpenHelper应该调用超级构造函数。
  2. onUpgrade()方法只会在版本的整数大于应用中运行的当前版本时被调用。
  3. 如果要调用onUpgrade()方法,则需要在代码中增加版本号。

可能是我太晚了,但我想分享我简短而甜蜜的回答。 请检查答案是否有同样的问题。 这一定会帮助你。 没有更深的规格。

如果您对创build表的语法有信心,那么当您在同一个表中添加新列时,可能会发生这种情况。

1)从您的设备卸载并再次运行。

要么

2)设置 – >应用程序 – > ClearData

要么

3)在你的“DatabaseHandler”类中更改DATABASE_VERSION (如果你添加了新的列而不是自动升级)

 public DatabaseHandler(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } 

要么

4)改变你的“DatabaseHandler”类中的DATABASE_NAME (我面临同样的问题,但是我通过改变DATABASE_NAME成功)。

在扩展SQLiteOpenHelper时要记住的SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); – 这应该被调用构造函数的第一行
  2. 重写onCreateonUpgrade (如果需要)
  3. 只有在执行getWritableDatabase()getReadableDatabase()时,才会调用onCreate 。 这只会在第一步指定的DBName不可用时调用一次。 您可以在onCreate方法上添加创build表查询
  4. 每当你想添加新表,只需更改DBversion并在onUpgrade表中执行查询,或者只需卸载然后安装应用程序。

你可以像创build数据库和表

 public class DbHelper extends SQLiteOpenHelper { private static final String DBNAME = "testdatbase.db"; private static final int VERSION = 1; public DbHelper(Context context) { super(context, DBNAME, null, VERSION); // TODO Auto-generated constructor stub } @Override public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub db.execSQL("create table BookDb(id integer primary key autoincrement,BookName text,Author text,IssuedOn text,DueDate text,Fine text,Totalfine text"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS BookDb"); onCreate(db); } } 

注意:如果你想创build另一个表或添加列或没有这样的表,只需增加VERSION

从模拟器或设备上卸载您的应用程序。 再次运行应用程序。 (当数据库已经存在时,OnCreate()不会被执行)

没有find这样的表主要是当你没有打开与getwritabledata()SQLiteOpenHelper类之前,你还必须调用与数据库名称和版本的构造函数。 并且在SQLiteOpenHelper类中给定的版本号中有升级值时调用SQLiteOpenHelper

下面是代码片段(找不到这样的列可能是因为列名中的拼写):

 public class database_db { entry_data endb; String file_name="Record.db"; SQLiteDatabase sq; public database_db(Context c) { endb=new entry_data(c, file_name, null, 8); } public database_db open() { sq=endb.getWritableDatabase(); return this; } public Cursor getdata(String table) { return sq.query(table, null, null, null, null, null, null); } public long insert_data(String table,ContentValues value) { return sq.insert(table, null, value); } public void close() { sq.close(); } public void delete(String table) { sq.delete(table,null,null); } } class entry_data extends SQLiteOpenHelper { public entry_data(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); // TODO Auto-generated constructor stub } @Override public void onCreate(SQLiteDatabase sqdb) { // TODO Auto-generated method stub sqdb.execSQL("CREATE TABLE IF NOT EXISTS 'YOUR_TABLE_NAME'(Column_1 text not null,Column_2 text not null);"); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { onCreate(db); } } 

如果您忘记提供一个“名称”string作为构造函数的第二个参数,它会创build一个“内存”数据库,当您closures该应用程序时将被删除。

您的数据库名称必须以.db结尾,您的查询string也必须有一个终止符(;)

Sqliteopenhelper的方法有方法创build和升级,创build时使用,当任何表第一次创build和升级方法将调用每当表的列号改变。