什么时候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()
)中更改表架构时,应确保数据库已更新。 两个主要方法:
-
删除旧的数据库文件,以便再次运行
onCreate()
。 在开发时,这通常是首选,您可以控制安装的版本,数据丢失不是问题。 一些方法来删除数据库文件:-
卸载应用程序。 使用应用程序pipe理器或
adb uninstall your.package.name
从shell中adb uninstall your.package.name
。 -
清除应用程序数据 使用应用程序pipe理器。
-
-
增加数据库版本,以便调用
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); } }
注意情况1
和2
的缺失break
声明。 这就是我所说的增量升级。
说如果旧版本是2
,新版本是4
,那么逻辑将数据库从2
升级到3
,然后升级到4
如果旧版本为3
,新版本为4
,则只运行升级逻辑3
至4
onCreate()
-
当我们第一次创build数据库(即数据库不存在)
onCreate()
创build数据库与SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
传递的SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
-
onCreate()
方法创build您定义的表并执行您编写的任何其他代码。 但是,只有在应用程序数据目录中缺lessSQLite文件(/data/data/your.apps.classpath/databases
)时才会调用此方法。 -
如果您更改了代码并在模拟器中重新启动,则不会调用此方法。 如果你想运行
onCreate()
,你需要使用adb来删除SQLite数据库文件。
onUpgrade()
-
SQLiteOpenHelper
应该调用超级构造函数。 -
onUpgrade()
方法只会在版本的整数大于应用中运行的当前版本时被调用。 - 如果要调用
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
-
super(context, DBName, null, DBversion);
– 这应该被调用构造函数的第一行 - 重写
onCreate
和onUpgrade
(如果需要) - 只有在执行
getWritableDatabase()
或getReadableDatabase()
时,才会调用onCreate
。 这只会在第一步指定的DBName
不可用时调用一次。 您可以在onCreate
方法上添加创build表查询 - 每当你想添加新表,只需更改
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和升级方法将调用每当表的列号改变。