SQLiteException虽然删除了我的应用程序

时间:2018-04-24 07:22:04

标签: android android-sqlite

我已经改变了我的表结构,并在onCreate()中编写了它。我删除了我的应用程序和所有sqlite数据,然后安装应用程序并使用新的表结构。但是,某种方式sqlite数据不会被删除。我删除了申请。然后安装它,不调用onCreate(),发生以下错误:

android.database.sqlite.SQLiteException: Can't downgrade database from version 3 to 1

我打开设置 - >然后清除应用程序的缓存和数据。然后删除该应用程序。但是我仍然采取相同的错误仍然onCreate()永远不会被调用。

我阅读了类似的问题并应用了以下解决方案,但这不起作用。

MyDBHandler dbHandler = new MyDBHandler(this,null);
dbHandler.getWritableDatabase();

public class MyDBHandler extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 1;
    private static final String DATABASE_NAME = "customers.db";

    public MyDBHandler(Context context, SQLiteDatabase.CursorFactory factory) {
        super(context, DATABASE_NAME, factory, DATABASE_VERSION);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }

    @Override
    public void onCreate(SQLiteDatabase db)
    {
        // here is never called
        String query1 = "CREATE TABLE IF NOT EXISTS " + TABLE_DRAWINGS + "(" +
                COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT ," +
                COLUMN_IMAGENAME + " TEXT , " +
                COLUMN_DRAWVERSION + " INTEGER ); ";

        String query2 = "CREATE TABLE  IF NOT EXISTS " + TABLE_ACTIONS + "(" +
                COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT ," +
                COLUMN_DRAWINGSID + " INTEGER , " +
                COLUMN_ACTION + " BLOB ," +
                " FOREIGN KEY( " +  COLUMN_DRAWINGSID   + " ) REFERENCES " + TABLE_DRAWINGS + "( "+ COLUMN_ID + " ));";

        String query3 = "CREATE TABLE  IF NOT EXISTS " + TABLE_MYWORK + "(" +
                COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT ," +
                COLUMN_DRAWINGSID + " INTEGER , " +
                COLUMN_ORDER + " INTEGER , " +
                " FOREIGN KEY( " + COLUMN_DRAWINGSID  + " ) REFERENCES " + TABLE_DRAWINGS + "( "+ COLUMN_ID + " ));";

        db.execSQL(query1);
        db.execSQL(query2);
        db.execSQL(query3);
    }
}

在链接(Can't downgrade database from version 2 to 1 even after fresh install and re-run)中的类似问题中,第一个答案与我的案例相符:

The device that you're running the code on has a database file of version 2.

但是,我的问题是为什么无法删除该数据库文件。没有答案。答案强迫我使用onDowngrade()或onUpgrade()方法,虽然我不应该使用它为我的情况,因为我尚未发布我的应用程序。如果我对我的测试应用程序的每个ddl更改使用onDowngrade()或onUpgrade(),我认为这将是一个糟糕的解决方案。

我在不同的设备和模拟器中测试了我的应用程序,并且该设备没有错误。 那么第一个设备有什么问题。为什么无法删除sqlite数据?为什么onCreate永远不会被调用?

3 个答案:

答案 0 :(得分:2)

以下应该有效(当我测试它时)。它会将版本重置为1,然后删除所有表格,然后调用onCreate方法。

假设您已经通过删除应用程序的数据或卸载应用程序然后重新运行应用程序并且失败而重试。

对MyDBHandler类进行了3次更改,并对创建MyDBhandler实例的活动进行了更改。

  1. 根据
  2. 添加新的类成员变量

    : -

       private boolean resetversion = false;
    
    1. 更改构造函数以包含一个额外参数,以便可以按照
    2. 传递和设置上述参数

      : -

      public MyDBHandler(
                  Context context, 
                  SQLiteDatabase.CursorFactory factory, 
                  boolean resetversion) { //<<<< CHANGED (added boolean resetversion)
      
          super(context, DATABASE_NAME, factory, DATABASE_VERSION);
          this.resetversion = resetversion; //<<<< ADDED
      }
      
      1. onConfigure方法添加覆盖(即添加以下方法)
      2. : -

        @Override
        public void onConfigure(SQLiteDatabase db) {
            super.onConfigure(db);
            if (resetversion) {
                db.execSQL("pragma user_version = 1");
                db.execSQL("DROP TABLE IF EXISTS " + TABLE_MYWORK);
                db.execSQL("DROP TABLE IF EXISTS " + TABLE_ACTIONS);
                db.execSQL("DROP TABLE IF EXISTS " + TABLE_DRAWINGS);
                onCreate(db);
            }
        }
        
        • 以相反的顺序掉落,以免因外国钥匙而导致冲突。

        1. 更改
        2. : -

              MyDBHandler dbHandler = new MyDBHandler(this,null);
              dbHandler.getWritableDatabase();
          

          : -

              MyDBHandler dbHandler = new MyDBHandler(this,null,false); //<<<< Added ,false
              dbHandler.getWritableDatabase();
          
          1. 运行应用程序,它应该失败并显示失败(仅测试)。

          2. 现在将其更改为使用 true 并运行。数据库版本应更改为1,删除3个表,然后通过调用onCreate方法重新创建。

          3. 在重新运行应用程序之前将true更改为false (您应该撤消所有上述更改)。

          4. 这是我用于测试的完整myDBHanlder类: -

            public class MyDBHandler extends SQLiteOpenHelper {
            
                private static final int DATABASE_VERSION = 1;
                private static final String DATABASE_NAME = "customers.db";
            
                // Added the following to mimic your definitions
                private static final String COLUMN_ID = BaseColumns._ID;
                private static final String TABLE_DRAWINGS = "drwaings";
                private static final String COLUMN_IMAGENAME = "imagename";
                private static final String COLUMN_DRAWVERSION = "drawversion";
                private static final String TABLE_ACTIONS = "actions";
                private static final String COLUMN_DRAWINGSID = "drawingsid";
                private static final String COLUMN_ACTION = "actioncolumn";
                private static final String TABLE_MYWORK = "mywork";
                private static final String COLUMN_ORDER = "ordercolumn";
            
                private boolean resetversion = false; //<<<< ADDED 
            
                public MyDBHandler(Context context, SQLiteDatabase.CursorFactory factory, boolean resetversion) {
                    super(context, DATABASE_NAME, factory, DATABASE_VERSION);
                    this.resetversion = resetversion;
                }
            
                @Override
                public void onConfigure(SQLiteDatabase db) {
                    super.onConfigure(db);
                    if (resetversion) {
                        db.execSQL("pragma user_version = 1");
                        db.execSQL("DROP TABLE IF EXISTS " + TABLE_MYWORK);
                        db.execSQL("DROP TABLE IF EXISTS " + TABLE_ACTIONS);
                        db.execSQL("DROP TABLE IF EXISTS " + TABLE_DRAWINGS);
                        onCreate(db);
                    }
                }
            
                @Override
                public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
            
                }
            
                @Override
                public void onCreate(SQLiteDatabase db)
                {
                    // here is never called
                    String query1 = "CREATE TABLE IF NOT EXISTS " + TABLE_DRAWINGS + "(" +
                            COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT ," +
                            COLUMN_IMAGENAME + " TEXT , " +
                            COLUMN_DRAWVERSION + " INTEGER ); ";
            
                    String query2 = "CREATE TABLE  IF NOT EXISTS " + TABLE_ACTIONS + "(" +
                            COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT ," +
                            COLUMN_DRAWINGSID + " INTEGER , " +
                            COLUMN_ACTION + " BLOB ," +
                            " FOREIGN KEY( " +  COLUMN_DRAWINGSID   + " ) REFERENCES " + TABLE_DRAWINGS + "( "+ COLUMN_ID + " ));";
            
                    String query3 = "CREATE TABLE  IF NOT EXISTS " + TABLE_MYWORK + "(" +
                            COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT ," +
                            COLUMN_DRAWINGSID + " INTEGER , " +
                            COLUMN_ORDER + " INTEGER , " +
                            " FOREIGN KEY( " + COLUMN_DRAWINGSID  + " ) REFERENCES " + TABLE_DRAWINGS + "( "+ COLUMN_ID + " ));";
            
                    db.execSQL(query1);
                    db.execSQL(query2);
                    db.execSQL(query3);
                }
            }
            

            我在一项活动中使用以下代码进行了测试: -

                MyDBHandler mydbhlpr = new MyDBHandler(this,null, true);
                mydbhlpr.getWritableDatabase();
                CommonSQLiteUtilities.logDatabaseInfo(mydbhlpr.getWritableDatabase());
            
            • 我首先使用它将版本设置为3以重现Can't downgrade database from version 3 to 1(工作。)
            • 注意CommonSQLiteUtilities是我用来检查数据库和游标的一些东西,它们在这里Are there any methods that assist with resolving common SQLite issues?
            • 然后我再次使用version = 1运行以确认它将数据库版本设置回1。

            结果是: -

            首先将DB版本设置为3: -

            04-24 10:30:42.417 1503-1503/? E/AndroidRuntime: FATAL EXCEPTION: main
                java.lang.RuntimeException: Unable to start activity ComponentInfo{fkdemo.foreignkeydemonstration/fkdemo.foreignkeydemonstration.MainActivity}: android.database.sqlite.SQLiteException: Can't downgrade database from version 3 to 1
                    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
                ........
            

            第二次运行,版本号设置为1: -

            04-24 10:33:54.690 1564-1564/fkdemo.foreignkeydemonstration D/SQLITE_CSU: PRAGMA -  sqlite_version = 3.7.11
                PRAGMA -  user_version = 1
                PRAGMA -  encoding = UTF-8
                PRAGMA -  auto_vacuum = 1
            04-24 10:33:54.694 1564-1564/fkdemo.foreignkeydemonstration D/SQLITE_CSU: PRAGMA -  cache_size = 2000
                PRAGMA -  foreign_keys = 0
                PRAGMA -  freelist_count = 0
                PRAGMA -  ignore_check_constraints = 0
            04-24 10:33:54.698 1564-1564/fkdemo.foreignkeydemonstration D/SQLITE_CSU: PRAGMA -  journal_mode = persist
                PRAGMA -  journal_size_limit = 524288
                PRAGMA -  locking_mode = normal
                PRAGMA -  max_page_count = 1073741823
            04-24 10:33:54.702 1564-1564/fkdemo.foreignkeydemonstration D/SQLITE_CSU: PRAGMA -  page_count = 7
                PRAGMA -  page_size = 4096
                PRAGMA -  recursive_triggers = 0
                PRAGMA -  reverse_unordered_selects = 0
                PRAGMA -  secure_delete = 0
                PRAGMA -  synchronous = 2
                PRAGMA -  temp_store = 0
                PRAGMA -  wal_autocheckpoint = 100
                Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
            04-24 10:33:54.706 1564-1564/fkdemo.foreignkeydemonstration D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
                Number of Indexes = 0
                Number of Foreign Keys = 0
                Number of Triggers = 0
                Table Name = sqlite_sequence Created Using = CREATE TABLE sqlite_sequence(name,seq)
                Table = sqlite_sequence ColumnName = name ColumnType =  Default Value = null PRIMARY KEY SEQUENCE = 0
                Table = sqlite_sequence ColumnName = seq ColumnType =  Default Value = null PRIMARY KEY SEQUENCE = 0
            04-24 10:33:54.710 1564-1564/fkdemo.foreignkeydemonstration D/SQLITE_CSU: Number of Indexes = 0
                Number of Foreign Keys = 0
                Number of Triggers = 0
                Table Name = drwaings Created Using = CREATE TABLE drwaings(_id INTEGER PRIMARY KEY AUTOINCREMENT ,imagename TEXT , drawversion INTEGER )
                Table = drwaings ColumnName = _id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
                Table = drwaings ColumnName = imagename ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
                Table = drwaings ColumnName = drawversion ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 0
            04-24 10:33:54.714 1564-1564/fkdemo.foreignkeydemonstration D/SQLITE_CSU: Number of Indexes = 0
                Number of Foreign Keys = 0
                Number of Triggers = 0
                Table Name = actions Created Using = CREATE TABLE actions(_id INTEGER PRIMARY KEY AUTOINCREMENT ,drawingsid INTEGER , actioncolumn BLOB , FOREIGN KEY( drawingsid ) REFERENCES drwaings( _id ))
                Table = actions ColumnName = _id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
                Table = actions ColumnName = drawingsid ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 0
                Table = actions ColumnName = actioncolumn ColumnType = BLOB Default Value = null PRIMARY KEY SEQUENCE = 0
                Number of Indexes = 0
            04-24 10:33:54.718 1564-1564/fkdemo.foreignkeydemonstration D/SQLITE_CSU: Number of Foreign Keys = 1
                    Column drawingsid References Table drwaings Column _id ON UPDATE Action=NO ACTION ON DELETE Action = NO ACTION MATCh Clause (unsopprted) = NONEID = 0SEQ = 0
                Number of Triggers = 0
                Table Name = mywork Created Using = CREATE TABLE mywork(_id INTEGER PRIMARY KEY AUTOINCREMENT ,drawingsid INTEGER , ordercolumn INTEGER ,  FOREIGN KEY( drawingsid ) REFERENCES drwaings( _id ))
                Table = mywork ColumnName = _id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
                Table = mywork ColumnName = drawingsid ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 0
                Table = mywork ColumnName = ordercolumn ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 0
                Number of Indexes = 0
            04-24 10:33:54.722 1564-1564/fkdemo.foreignkeydemonstration D/SQLITE_CSU: Number of Foreign Keys = 1
                    Column drawingsid References Table drwaings Column _id ON UPDATE Action=NO ACTION ON DELETE Action = NO ACTION MATCh Clause (unsopprted) = NONEID = 0SEQ = 0
                Number of Triggers = 0
            

            其他

            要使用FOREIGN KEYS,您需要使用PRAGMA来启用它们,建议在onConfigure中完成。因此,您应在MyDBHandler中添加以下内容: -

            @Override
            public void onConfigure(SQLiteDatabase db) {
                super.onConfigure(db);
                db.execSQL("pragma foreign_keys = ON"); //<<< turn FK handling on
            }
            

答案 1 :(得分:0)

在SQLITEOpenHelper Class中,版本号大于3.您无法降级到旧版本的db

public class YourHelperClassName extends SQLiteOpenHelper {

    public YourHelperClassName(Context c) {
            super(c, "YOUR_DBNAME", null, version_Number);
        }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //Add the Table creation code for new version here. Since this code works for the new user or when the user cleare data from settings.
    }
}

请参阅此问题,该问题可以帮助您Can't downgrade database from version 2 to 1 even after fresh install and re-run

答案 2 :(得分:-1)

MikeT的回答有一些有用的建议,但它没有给出我的问题的答案。我解决了这个问题,让我解释一下。

如前所述,无论我做什么,都无法删除sqlite数据库。下面是我的构造函数的旧版本:

public MyDBHandler(Context context, SQLiteDatabase.CursorFactory factory) {
    super(context, DATABASE_NAME, factory, DATABASE_VERSION);  // sqlite dosyasi This PC\Galaxy A3 2016\Phone\Android\data\com.lyrebirdstudio.mandala\files\customers.db lokasyonunda tutulur.
    Log.d("testxx","path : " + context.getFilesDir());
    mcontext = context;
}

日志:

04-25 12:09:31.681 16448-16448/com.test.myapp D/testxx: path : /data/user/0/com.test.myapp/files

换句话说,sqlite数据在此目录中,无法删除。

在构造函数中,我更改了super()的第二个参数。下面是我的构造函数的新版本:

public MyDBHandler(Context context, SQLiteDatabase.CursorFactory factory) {
    super(context, context.getExternalFilesDir(null)+ File.separator + DATABASE_NAME, factory, DATABASE_VERSION);  
    Log.d("testxy","path2 : " + context.getExternalFilesDir(null)+ File.separator + DATABASE_NAME);
    mcontext = context;
}

日志:

04-25 12:09:31.684 16448-16448/com.test.myapp D/testxy: path2 : /storage/emulated/0/Android/data/com.test.myapp/files/customers.db

通过使用此目录解决了无法删除的sqlite数据的问题。