在探索 Room 库和 RoomDatabase 类的功能时,我决定测试 query() 方法。由于官方文档中的描述并没有对其使用进行任何限制,因此我决定测试两个最简单的方法:SELECT 和 INSERT。
我正在使用一个简单的数据库测试查询。我的选择看起来像这样:
Cursor cursor = db.query("select * from artist”, null);
艺术家表说明如下:
@Entity
public class Artist {
@PrimaryKey
public int Artist_id;
public String Name;
}
这个方法效果很好,返回了一个 Cursor,我可以用它查看表数据。
但是当我决定尝试使用如下 INSERT 方法时:
Cursor cursor = db.query("insert into artist (name) values('Candido');”, null);
然后发现没有发生向表中插入新行的情况。我决定通过调试来找出为什么query()方法执行select操作并执行插入,但在库代码中找不到发生检查的地方。然后我决定执行 SELECT 和 INSERT,但是使用 SQLiteDatabase 类中的 rawQuery() 方法,结果是相同的。
在库类SQLiteDirectCursorDriver中逐步调试时,调试时,程序执行以下方法:
public Cursor query(CursorFactory factory, String[] selectionArgs) {
final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
final Cursor cursor;
try {
query.bindAllArgsAsStrings(selectionArgs);
if (factory == null) {
cursor = new SQLiteCursor(this, mEditTable, query);
} else {
cursor = factory.newCursor(mDatabase, this, mEditTable, query);
}
} catch (RuntimeException ex) {
query.close();
throw ex;
}
mQuery = query;
return cursor;
}
这是在创建 Cursor 对象期间调用的方法,它是由我正在测试的 query() 方法返回的。 创建 SQLiteQuery 时,其构造函数会调用父类 SQLiteProgram 的构造函数,其中包含以下几行:
db.getThreadSession().prepare(mSql,
db.getThreadDefaultConnectionFlags(assumeReadOnly),
cancellationSignalForPrepare, info);
我假设对数据库的查询发生在这个地方,但情况可能并非如此,因为 SQLiteSession 类的prepare()方法的描述说该方法“准备要执行的语句,但不绑定其参数或执行它”。 如果我们返回到 query() 方法,即我上面描述的代码,那么您应该注意以下行
cursor = new SQLiteCursor(this, mEditTable, query);
构造函数描述为:“执行查询并通过 Cursor 接口提供对其结果集的访问。”
但是如果我打开类构造函数的代码和父类构造函数的代码,那么我没有找到在数据库中执行我的sql的代码。
我无法理解对数据库的 SELECT/INSERT 查询是在哪里执行的,在什么地方,在什么类和方法中发生这种情况?光标随后处理的数据在哪里? 请帮我理解这个过程的内部结构。
代码在Android 13 API 33模拟器arm64-v8a上测试
我无法理解对数据库的 SELECT/INSERT 查询在哪里执行
我不认为你需要这样做。
光标随后处理的数据在哪里?
和
然后发现没有发生向表中插入新行的情况。 没有数据。 INSERT 不返回任何数据。此外,由于它不返回任何数据,因此被视为不值得执行,因此不会执行 SQL(这是基于经验的假设,而不是调查底层代码)。
你可能会说,但是
@Insert
确实返回了artist_id,这是因为插入的底层代码(Room调用的SQLite API)在插入之后是另一个返回rowid的API调用(artist_id是一个的别名)。
更多内容(解决方案是使用官方文档不包含任何使用限制 好吧,当它说“使用参数查询数据库的便捷方法”时。。这意味着它不适用于更改数据库的操作。
execSQL