SQLiteException:如果存在这样的表,则不存在

时间:2018-11-25 14:36:31

标签: java android sqlite android-sqlite

我有一个外部数据库,我将其复制到内部存储中,我在设备文件资源管理器中检查是否已成功复制它,在这里找到它,我尝试更改版本并清除应用程序存储,但没有结果

enter image description here

这是我得到的错误:

java.lang.RuntimeException: Unable to start activity ComponentInfo{<PackageName>.MainActivity}: android.database.sqlite.SQLiteException: no such table: MSG_CAT (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM MSG_CAT
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2914)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3049)
  at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
  at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1809)
  at android.os.Handler.dispatchMessage(Handler.java:106)
  at android.os.Looper.loop(Looper.java:193)
  at android.app.ActivityThread.main(ActivityThread.java:6680)
  at java.lang.reflect.Method.invoke(Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

 Caused by: android.database.sqlite.SQLiteException: no such table: MSG_CAT (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM MSG_CAT
      at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
      at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:903)
      at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:514)
      at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
      at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
      at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
      at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
      at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1408)
      at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1347)
      at <PackageName>.database.DatabaseHelper.getListProduct(DatabaseHelper.java:60)
      at <PackageName>.MainActivity.onCreate(MainActivity.java:52)

我用来从资产文件夹创建和复制数据库的类是 :

public class DatabaseHelper extends SQLiteOpenHelper {

public static final String DBNAME = "msgDb.db";
public static final String DBLOCATION = "/data/data/<PackageName>/databases/";
private Context mContext;
private SQLiteDatabase mDatabase;

public DatabaseHelper(Context context) {
    super(context, DBNAME, null, 2);
    this.mContext = context;
}

@Override
public void onCreate(SQLiteDatabase db) {

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    if(newVersion>oldVersion)
        copyDatabase(mContext);
}

public void openDatabase() {
    String dbPath = mContext.getDatabasePath(DBNAME).getPath();
    if (mDatabase != null && mDatabase.isOpen()) {
        return;
    }
    mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
}

public void closeDatabase() {
    if (mDatabase != null) {
        mDatabase.close();
    }
}

private boolean copyDatabase(Context context) {
    try {
        InputStream inputStream = context.getAssets().open(DatabaseHelper.DBNAME);
        String outFileName = DatabaseHelper.DBLOCATION + DatabaseHelper.DBNAME;
        OutputStream outputStream = new FileOutputStream(outFileName);
        byte[]buff = new byte[1024];
        int length = 0;
        while ((length = inputStream.read(buff)) > 0) {
            outputStream.write(buff, 0, length);
        }
        outputStream.flush();
        outputStream.close();
        Log.d("MainActivity","DB copied");
        return true;
    }catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

public List<Category> getListProduct() {
    Category category = null;
    List<Category> CategoryList = new ArrayList<>();
    openDatabase();
    Cursor cursor = mDatabase.rawQuery("SELECT * FROM MSG_CAT", null);
    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
        category = new Category(cursor.getInt(0), cursor.getString(1), cursor.getDouble(2));
        CategoryList.add(category);
        cursor.moveToNext();
    }
    cursor.close();
    closeDatabase();
    return CategoryList;
}

public Category getProductById(int id) {
    Category product = null;
    openDatabase();
    Cursor cursor = mDatabase.rawQuery("SELECT * FROM MSG_CAT WHERE ID = ?", new String[]{String.valueOf(id)});
    cursor.moveToFirst();
    product = new Category(cursor.getInt(0), cursor.getString(1), cursor.getDouble(2));
    //Only 1 resul
    cursor.close();
    closeDatabase();
    return product;
}

表存在证明:

enter image description here

我尽一切努力解决了这个问题,但没有任何结果。

更新

我发现问题仅出在运行Android P的Pixel 2XL上,我在其他手机和模拟器上测试了该应用,并且运行良好。

2 个答案:

答案 0 :(得分:0)

在这里,onCreate回调在您的代码中为空。使用创建表的SQLite标准语法在onCreate回调中创建表:

@Override
public void onCreate(SQLiteDatabase db) {
//execute the query to create the table with columns;

db.execSQL(YOUR_QUERY);
}

然后卸载该应用程序,然后重新安装它以重新创建包含所有表的数据库。

答案 1 :(得分:0)


请注意

为方便起见,下面的 DatabseHelper 代码不包括 getListProduct getProductById 方法。


我认为从日志中可以明显看出该问题。但是基本上,如果数据库不存在,并且您要在打开数据库后复制数据库(没有数据库,它将不会被打开,因此不会进行复制)。

以下内容解决了一些问题。

主要问题是检查db文件是否位于预期位置。即它不会尝试打开数据库,而是查看文件是否存在。如果没有,它将在实例化DatabaseHelper时尝试执行任何操作来打开数据库之前复制该数据库。

此外,使用mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);打开数据库将导致打开数据库,而不会运行onUpgrade方法。那是因为您不是通过SQLiteOpenHelper子类打开数据库,所以它无济于事。

也许一个问题是您有<PackageName>。但是,对数据库路径进行硬编码可能会引起问题,因此该路径是根据Context的 getDatabasePath 方法(强烈建议仅在不将数据库放在其他位置的情况下才使用此方法)来确定

希望以下内容可以继续进行。 注意我强烈建议删除该应用程序的数据,然后再卸载该应用程序。

public class DatabaseHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "msgDb.db";
    public static final String DBLOCATION = "/data/data/<PackageName>/databases/"; //<<<<<<<<< Shouldn't hard code path, really this package name????
    private Context mContext;
    private SQLiteDatabase mDatabase;

    public DatabaseHelper(Context context) {
        super(context, DBNAME, null, 2);
        this.mContext = context;
        //<<<<<<<<<< Copy database if need be
        if (!ifDBExists()) {
            copyDatabase(context);
        }
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d("ONCREATE","WARNING!!!! onCreate method shopuldn't be invoked"); //<<<<<<<<<< ADDED

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion > oldVersion)
            Log.d("ONUPGRADE","Attempting to copy database"); //<<<<<<<<<< ADDED
            copyDatabase(mContext);
    }

    public void openDatabase() {
        String dbPath = mContext.getDatabasePath(DBNAME).getPath();
        if (mDatabase != null && mDatabase.isOpen()) {
            return;
        }
        mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
    }

    public void closeDatabase() {
        if (mDatabase != null) {
            mDatabase.close();
        }
    }

    /**
     * Check if the database file exists
     * @return
     */
    private boolean ifDBExists() {
        File db =  new File(mContext.getDatabasePath(DBNAME).getPath());
        if (db.exists()) return true;
        File dbdir = new File(db.getParent());
        if (!dbdir.exists()) {
            dbdir.mkdirs();
        }
        return false;
    }

    private boolean copyDatabase(Context context) {
        Log.d("COPYDATABASE","Initiating copy of database");
        try {
            InputStream inputStream = context.getAssets().open(DatabaseHelper.DBNAME);
            String outFileName = context.getDatabasePath(DBNAME).getAbsolutePath(); //<<<<<<<<<< CHANGED
            //String outFileName = DatabaseHelper.DBLOCATION + DatabaseHelper.DBNAME; // relies on hard coded
            int bytes_copied = 0;
            OutputStream outputStream = new FileOutputStream(outFileName);
            byte[] buff = new byte[1024];
            int length = 0;
            while ((length = inputStream.read(buff)) > 0) {
                outputStream.write(buff, 0, length);

            }
            outputStream.flush();
            outputStream.close();
            Log.d("MainActivity", "DB copied");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public void logMsgCatTable() {
        openDatabase();
        Cursor csr = mDatabase.query("MSG_CAT",null,null,null,null,null, null  );
        DatabaseUtils.dumpCursor(csr);
    }
}
  • 请注意删除日志消息。
  • 注意还请参阅/阅读评论。
  • 请继续阅读,因为上述内容仍然存在问题

按照非常基本的MainActivity运行上述程序:-

public class MainActivity extends AppCompatActivity {
    DatabaseHelper mDBHlpr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDBHlpr = new DatabaseHelper(this);
        mDBHlpr.logMsgCatTable();
    }
}

首次运行:-

018-11-26 11:25:47.286 2597-2597/? D/COPYDATABASE: Initiating copy of database
2018-11-26 11:25:47.287 2597-2597/? D/MainActivity: DB copied
2018-11-26 11:25:47.302 2597-2597/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@9bd3b6b
2018-11-26 11:25:47.302 2597-2597/? I/System.out: 0 {
2018-11-26 11:25:47.302 2597-2597/? I/System.out:    ID=1
2018-11-26 11:25:47.302 2597-2597/? I/System.out:    COL1=mcat col1 001
2018-11-26 11:25:47.303 2597-2597/? I/System.out:    COL2=mcat col2 001
2018-11-26 11:25:47.303 2597-2597/? I/System.out: }
2018-11-26 11:25:47.303 2597-2597/? I/System.out: <<<<<
  • 请注意DBVERSION(未设置/触摸SQLite中的aka user_version)

第二次运行:-

如上所述,除了日志中的前2条消息(即,由于DBVERSION设置为2,因此未复制DB或未运行onUpgrade)。

第三次比赛

在SQLite工具中添加了另一行,将数据库复制回了Assets文件夹,但没有更改user_version。用修改后的数据库替换原始数据库并增加DBVERSION(super(context, DBNAME, null, 3);)之后:-

按上述方法不会复制更新的数据库,因为onUpgrade不会在您按助手时运行。

将代码修改为:-

public class DatabaseHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "msgDb.db";
    public static final String DBLOCATION = "/data/data/<PackageName>/databases/"; //<<<<<<<<< Shouldn't hard code path, really this package name????
    public static final int DBVERSION = 3; //<<<<<<<<<< ADDED STAGE 2
    private Context mContext;
    private SQLiteDatabase mDatabase;

    public DatabaseHelper(Context context) {
        super(context, DBNAME, null, DBVERSION); //<<<<<<<<<<CHANGED STAGE2 
        this.mContext = context;
        //<<<<<<<<<< Copy database if need be
        if (!ifDBExists()) {
            copyDatabase(context);
        }
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d("ONCREATE","WARNING!!!! onCreate method shopuldn't be invoked"); //<<<<<<<<<< ADDED
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion > oldVersion)
            Log.d("ONUPGRADE","Attempting to copy database"); //<<<<<<<<<< ADDED
            copyDatabase(mContext);
    }

    //<<<<<<<<<< CHANGED STAGE2 (checks the user_version, closes the DB does the copy, then opens the DB)
    public void openDatabase() {
        String dbPath = mContext.getDatabasePath(DBNAME).getPath();
        if (mDatabase != null && mDatabase.isOpen()) {
            return;
        }
        mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
        if (mDatabase.getVersion() < DBVERSION) {
            mDatabase.close();
            copyDatabase(mContext);
            mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
        }
        if(!mDatabase.isOpen()) {
            Log.d("OPENDATABASE","For some reason the Database cannot be opened!!!!!!!!!! ");
        }
    }

    public void closeDatabase() {
        if (mDatabase != null) {
            mDatabase.close();
        }
    }

    /**
     * Check if the database file exists
     * @return
     */
    private boolean ifDBExists() {
        File db =  new File(mContext.getDatabasePath(DBNAME).getPath());
        if (db.exists()) return true;
        File dbdir = new File(db.getParent());
        if (!dbdir.exists()) {
            dbdir.mkdirs();
        }
        return false;
    }

    private boolean copyDatabase(Context context) {
        Log.d("COPYDATABASE","Initiating copy of database");
        try {
            InputStream inputStream = context.getAssets().open(DatabaseHelper.DBNAME);
            String outFileName = context.getDatabasePath(DBNAME).getAbsolutePath(); //<<<<<<<<<< CHANGED
            //String outFileName = DatabaseHelper.DBLOCATION + DatabaseHelper.DBNAME; // relies on hard coded
            int bytes_copied = 0;
            OutputStream outputStream = new FileOutputStream(outFileName);
            byte[] buff = new byte[1024];
            int length = 0;
            while ((length = inputStream.read(buff)) > 0) {
                outputStream.write(buff, 0, length);

            }
            outputStream.flush();
            outputStream.close();
            Log.d("MainActivity", "DB copied");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public void logMsgCatTable() {
        openDatabase();
        Cursor csr = mDatabase.query("MSG_CAT",null,null,null,null,null, null  );
        DatabaseUtils.dumpCursor(csr);
    }
}

注意上面的代码应作为解决问题的基础。

第四轮:-

2018-11-26 12:03:28.984 3188-3188/so53468569.so53468569messages D/COPYDATABASE: Initiating copy of database
2018-11-26 12:03:28.985 3188-3188/so53468569.so53468569messages D/MainActivity: DB copied
2018-11-26 12:03:28.993 3188-3188/so53468569.so53468569messages I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@7edd361
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: 0 {
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out:    ID=1
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out:    COL1=mcat col1 001
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out:    COL2=mcat col2 001
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: }
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: 1 {
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out:    ID=2
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out:    COL1=mcat col1 002
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out:    COL2=mcat col2 002
2018-11-26 12:03:28.995 3188-3188/so53468569.so53468569messages I/System.out: }
2018-11-26 12:03:28.995 3188-3188/so53468569.so53468569messages I/System.out: <<<<<
相关问题