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

我已经在我的SQLiteOpenHelper onCreate()中创建了我的表

SQLiteException: no such table

SQLiteException: no such column

错误。为什么?

注意:

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

133603 次浏览

SQLiteOpenHelper onCreate()onUpgrade()回调函数在数据库实际打开时被调用,例如调用getWritableDatabase()。在创建数据库帮助对象本身时,不会打开数据库。

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

onCreate()仅在数据库文件不存在且刚刚创建时运行。如果onCreate()成功返回(没有抛出异常),则假定数据库是使用所请求的版本号创建的。作为暗示,你不应该自己在onCreate()中捕获SQLExceptions。

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

当在code (onCreate())中更改表模式时,应确保数据库已更新。两种主要方法:

  1. 删除旧的数据库文件,使onCreate()再次运行。在开发阶段,这通常是首选的,因为您可以控制已安装的版本,并且数据丢失不是问题。删除数据库文件的方法:

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

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

    • 李< / ul > < / >
    • 增加数据库版本,以便调用onUpgrade()。这稍微复杂一些,因为需要更多的代码。

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

      • 对于已发布的版本,你应该在onUpgrade()中实现数据迁移,这样你的用户就不会丢失他们的数据。

      • 李< / ul > < / >

根据Jaskey的要求,进一步补充这里的缺失点

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

Catch是构造函数

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

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

正如在旧的答案中已经解释过的,如果具有该名称的数据库不存在,它将触发onCreate

下面用一个例子解释了onUpgrade的情况。

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

现在假设你计划给应用程序的第三个版本,db版本为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);
}
}

注意在case 12中缺少break语句。这就是我所说的增量升级。

假设旧版本是2,新版本是4,那么逻辑将把数据库从2升级到3,然后再升级到4

如果旧版本是3,新版本是4,它将只运行从34的升级逻辑

onCreate()

  1. 当我们第一次创建数据库(即数据库不存在)onCreate()创建数据库的版本是传入的 李SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) < / p > < / >

  2. onCreate()方法正在创建你所定义的表并执行你所编写的任何其他代码。但是,这个方法只会在应用程序的数据目录(/data/data/your.apps.classpath/databases)中缺少SQLite文件时被调用。

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

onUpgrade()

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

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

扩展SQLiteOpenHelper时要记住的要点

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

Sqliteopenhelper的方法有create方法和upgrade方法,create方法在任何表第一次创建时使用,而upgrade方法将在每次表的列数发生变化时调用。

也许我太晚了,但我想分享我简短而甜蜜的答案。 请检查< >强回答< / >强是否有同样的问题。它肯定会对你有帮助。

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

1)从设备上卸载并重新运行。

2)设置—> app—> ClearData

在你的DatabaseHandler类中改变DATABASE_VERSION(如果你添加了新列,它会自动升级)

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

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

没有找到这样的表主要是当你没有使用getwritabledata()打开SQLiteOpenHelper类时,在此之前你还必须使用databasename &调用make构造函数;的版本。 当SQLiteOpenHelper类中给出的版本号中存在升级值时,将调用OnUpgrade

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

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


}

您可以创建数据库&表像

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

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

数据库名必须以.db结尾,查询字符串必须有结束符(;)

如果你忘记提供一个“name”字符串作为构造函数的第二个参数,它会创建一个“内存中”数据库,当你关闭应用程序时,这个数据库会被擦除。

onCreate在需要创建表时第一次被调用。我们需要重写这个方法,在这里我们编写了由SQLiteDatabase执行的表创建脚本。execSQL方法。在第一次部署中执行后,此方法将不再被调用。

< >强onUpgrade 当数据库版本升级时调用此方法。假设第一次部署时,数据库版本为1,在第二次部署时,数据库结构发生了变化,例如在表中增加了额外的列。假设数据库版本现在是2 .

在DatabaseHandler/DatabaseManager类中重新检查您的查询(您曾经使用过的类)

Sqlite数据库覆盖两种方法

< p > 1) onCreate (): 该方法仅在应用程序第一次启动时调用一次。所以它只调用了一次

< p > 2) onUpgrade () 当我们改变数据库版本时,这个方法被调用,然后这个方法被调用。它用于改变表结构,例如在创建DB Schema

后添加新列

在我的例子中,我使用<string-array>从xml文件中获取项目,在那里我存储了<item>s。在这些__abc1中,我保存SQL字符串并逐个应用databaseBuilder.addMigrations(migration)。我犯了一个错误,忘记在quote之前添加\,并得到了异常:

android.database.sqlite.SQLiteException:没有这样的列:some_value(代码1 SQLITE_ERROR):,而编译:INSERT INTO table_name(id, name) VALUES(1, some_value)

所以,这是一个正确的变体:

<item>
INSERT INTO table_name(id, name) VALUES(1, \"some_value\")
</item>