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

时间:2014-02-19 13:31:07

标签: android sqlite android-sqlite sqlexception sqliteopenhelper

我已在SQLiteOpenHelper onCreate()创建了我的表格,但收到了

SQLiteException: no such table

SQLiteException: no such column

错误。为什么呢?

  

注意:

     

(这是每周数十个类似问题的合并摘要。试图在这里提供一个“规范的”社区维基问题/答案,以便所有这些问题可以直接提供给参考。)

15 个答案:

答案 0 :(得分:342)

实际打开数据库时会调用

SQLiteOpenHelper onCreate()onUpgrade()回调,例如通过调用getWritableDatabase()。创建数据库帮助程序对象本身时,不会打开数据库。

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

onCreate()仅在数据库文件不存在且刚刚创建时运行。如果onCreate()成功返回(不抛出异常),则假定使用请求的版本号创建数据库。这意味着,您不应该自己在SQLException中抓住onCreate()

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

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

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

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

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

  2. 增加数据库版本,以便调用onUpgrade()。由于需要更多代码,因此稍微复杂一些。

    • 对于数据丢失不成问题的开发时架构升级,您只需使用execSQL("DROP TABLE IF EXISTS <tablename>")删除现有表并调用onCreate()即可重新创建数据库。

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

答案 1 :(得分:95)

根据Jaskey的请求,在此处进一步添加缺失点

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

catch是构造函数

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

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

正如旧答案中已经解释的那样,如果名称不存在的数据库,则会触发onCreate

以下说明解释了onUpgrade案例。

说,您的第一个应用程序版本具有DatabaseHelper(扩展SQLiteOpenHelper),构造函数将版本传递为1,然后您提供了一个升级的应用程序,其中包含已通过版本的新源代码作为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);
  }
}

请注意break1案例中遗失的2语句。这就是增量升级的意思。

如果旧版本为2且新版本为4,则逻辑会将数据库从2升级到3,然后升级到4 }

如果旧版本为3且新版本为4,则只会将3的升级逻辑运行到4

答案 2 :(得分:20)

<强> onCreate()

  1. 当我们第一次创建DataBase时(即数据库不存在)onCreate()使用传入的版本创建数据库 SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

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

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

  4. <强> onUpgrade()

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

答案 3 :(得分:9)

可能是我来不及但是我想分享我简短而又甜蜜的答案。 请检查Answer是否存在同样的问题。它一定会帮到你。没有更深入的规范。

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

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

OR

2)设置 - &gt; app - &gt; ClearData

OR

3)在&#34; DatabaseHandler&#34;中更改DATABASE_VERSION class(如果添加了新列,则会自动升级)

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

OR

4)在&#34; DatabaseHandler&#34;中更改DATABASE_NAME上课(我遇到了同样的问题。但我通过改变DATABASE_NAME来取得成功。)

答案 4 :(得分:4)

延长SQLiteOpenHelper

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

答案 5 :(得分:2)

您可以创建数据库&amp;表格如

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

答案 6 :(得分:2)

当需要创建表时,首次调用

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

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

答案 7 :(得分:1)

找不到这样的表主要是因为你没有用SQLiteOpenHelper打开getwritabledata()类,在此之前你还必须调用带有databasename&amp;的make构造函数。版。 只要OnUpgrade类中给出的版本号有升级值,就会调用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);
    }

}

答案 8 :(得分:1)

如果您忘记提供姓名&#34; string作为构造函数的第二个参数,它创建了一个&#34; in-memory&#34;关闭应用程序时会删除的数据库。

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

在您的DatabaseHandler / DatabaseManager类中重新检查您的查询(无论您用过什么)

答案 12 :(得分:0)

Sqlite数据库覆盖两种方法

1)onCreate(): 首次启动应用程序时,仅调用一次此方法。因此它只调用了一次

2)onUpgrade() 更改数据库版本时调用此方法,然后调用此方法。该方法用于更改表结构,例如在创建数据库模式后添加新列

答案 13 :(得分:0)

在我的情况下,我使用<string-array>从XML文件中获取项目,我在其中存储了<item>。在这些<item>中,我持有SQL字符串,并与databaseBuilder.addMigrations(migration)一一对应。我犯了一个错误,忘记在引号前添加\并得到了例外:

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>

答案 14 :(得分:-2)

Sqliteopenhelper的方法有方法创建和升级,在第一次创建任何表时使用create,每当表的列数改变时,都会调用upgrade方法。