我已经改变了我的表结构,并在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永远不会被调用?
答案 0 :(得分:2)
以下应该有效(当我测试它时)。它会将版本重置为1,然后删除所有表格,然后调用onCreate
方法。
假设您已经通过删除应用程序的数据或卸载应用程序然后重新运行应用程序并且失败而重试。
对MyDBHandler类进行了3次更改,并对创建MyDBhandler实例的活动进行了更改。
: -
private boolean resetversion = false;
: -
public MyDBHandler(
Context context,
SQLiteDatabase.CursorFactory factory,
boolean resetversion) { //<<<< CHANGED (added boolean resetversion)
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
this.resetversion = resetversion; //<<<< ADDED
}
onConfigure
方法添加覆盖(即添加以下方法): -
@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);
}
}
: -
MyDBHandler dbHandler = new MyDBHandler(this,null);
dbHandler.getWritableDatabase();
到
: -
MyDBHandler dbHandler = new MyDBHandler(this,null,false); //<<<< Added ,false
dbHandler.getWritableDatabase();
运行应用程序,它应该失败并显示失败(仅测试)。
现在将其更改为使用 true 并运行。数据库版本应更改为1,删除3个表,然后通过调用onCreate
方法重新创建。
在重新运行应用程序之前将true更改为false (您应该撤消所有上述更改)。
这是我用于测试的完整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());
Can't downgrade database from version 3 to 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数据的问题。