安卓底朝天 —— android.database.sqlite.SQLiteDatabase.execSQL::String,Object: 调用栈
类搜索范围:android.database.sqlite:SQLiteDatabase,SQLiteStatement,SQLiteClosable,SQLiteProgram,SQLiteSession,SQLiteConnectionPool,SQLiteConnection&android.database.DatabaseUtils
如果是查询
查询分两步,第一步获取 Cursor,第二步使用 Cursor 获取数据
第一步不会真的去查数据库,第二步才会。
第一步的调用栈:
android.database.sqlite.SQLiteCursorDriver.query::CursorFactory,String: 由子类函数实现:
android.database.sqlite.SQLiteDirectCursorDriver.query::CursorFactory,String:,但这个函数并没有进行查询。
下面是这个子类函数的源码,可以看出来,它除了 new 对象什么也没有干。
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;
}
第二步的调用栈,以SQLiteCursor.getCount()为例:
什么是 CursorWindow 呢?源码文档中的解释:
* A buffer containing multiple cursor rows.
* <p>
* A {@link CursorWindow} is read-write when initially created and used locally.
* When sent to a remote process (by writing it to a {@link Parcel}), the remote process
* receives a read-only view of the cursor window. Typically the cursor window
* will be allocated by the producer, filled with data, and then sent to the
* consumer for reading.
* </p>
查询时的参数传递(SQL语句的传递)
下面我们看看你传给的 SQL 语句是如何被消费的:
如果是 UPDATE 或者 DELETE 一类的 SQL 语句
看看函数 android.database.sqlite.SQLiteConnection.executeForChangedRowCount::String,Object,CancellationSignal: 的注释:
/**
* Executes a statement that returns a count of the number of rows
* that were changed. Use for UPDATE or DELETE SQL statements.
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were changed.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
* @throws OperationCanceledException if the operation was canceled.
*/
public int executeForChangedRowCount(String sql, Object[] bindArgs, CancellationSignal cancellationSignal) {
。。。。。。
}
// 这个函数没有注释,但它是与 c++ 层代码的接口函数,因为有 native 修饰,表示它是 c++ 实现
private static native int nativeExecuteForChangedRowCount(long connectionPtr, long statementPtr);
这个函数明确表明自己是用于 UPDATE 或者 DELETE 一类的 SQL 语句,也就是说这个调用栈不适用于创建表与删除表的操作。
UPDATE 或者 DELETE 一类的 SQL 语句的参数传递
下面我们看看你传给的 SQL 语句是如何被消费的:
函数 android.database.sqlite.SQLiteConnection.executeForChangedRowCount::String,Object,CancellationSignal:Parameter1 把你的 SQL 语句传给 android.database.sqlite.SQLiteConnection.acquirePreparedStatement::String:Parameter1,使它从一个字符串变成一个 android.database.sqlite.SQLiteConnection.PreparedStatement 对象,这个对象拥有一个指针指向 c++ 层的一个对象,后面对 PreparedStatement 对象的处理就由 c++ 层完成了。
希望你能看懂下面的图
如果是创建表与删除表一类的 SQL 语句
看看函数 android.database.sqlite.SQLiteStatement.execute::: 的注释:
/**
* Execute this SQL statement, if it is not a SELECT / INSERT / DELETE / UPDATE, for example
* CREATE / DROP table, view, trigger, index etc.
*
* @throws android.database.SQLException If the SQL string is invalid for
* some reason
*/
public void execute() {
acquireReference();
try {
getSession().execute(getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} finally {
releaseReference();
}
}
这里明确说明是执行 CREATE / DROP table, view, trigger, index etc. 的SQL 语句。
创建表与删除表一类的 SQL 语句的另一个调用栈
函数 android.database.sqlite.SQLiteDatabase.execSQL::String,Object: 的注释:
/**
* Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
* <p>
* For INSERT statements, use any of the following instead.
* <ul>
* <li>{@link #insert(String, String, ContentValues)}</li>
* <li>{@link #insertOrThrow(String, String, ContentValues)}</li>
* <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li>
* </ul>
* <p>
* For UPDATE statements, use any of the following instead.
* <ul>
* <li>{@link #update(String, ContentValues, String, String[])}</li>
* <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li>
* </ul>
* <p>
* For DELETE statements, use any of the following instead.
* <ul>
* <li>{@link #delete(String, String, String[])}</li>
* </ul>
* <p>
* For example, the following are good candidates for using this method:
* <ul>
* <li>ALTER TABLE</li>
* <li>CREATE or DROP table / trigger / view / index / virtual table</li>
* <li>REINDEX</li>
* <li>RELEASE</li>
* <li>SAVEPOINT</li>
* <li>PRAGMA that returns no data</li>
* </ul>
* </p>
* <p>
* When using {@link #enableWriteAheadLogging()}, journal_mode is
* automatically managed by this class. So, do not set journal_mode
* using "PRAGMA journal_mode'<value>" statement if your app is using
* {@link #enableWriteAheadLogging()}
* </p>
*
* @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
* not supported.
* @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
* @throws SQLException if the SQL string is invalid
*/
public void execSQL(String sql, Object[] bindArgs) throws SQLException {
。。。。。。
}
如果你想简单的查第一个字段
函数 android.database.DatabaseUtils.stringForQuery::SQLiteDatabase,String,String: 的注释:
/**
* Utility method to run the query on the db and return the value in the
* first column of the first row.
*/
public static String stringForQuery(SQLiteDatabase db, String query, String[] selectionArgs) {
SQLiteStatement prog = db.compileStatement(query);
try {
return stringForQuery(prog, selectionArgs);
} finally {
prog.close();
}
}
它返回查询结果的第一行第一列(first column of the first row)。如果你的表的第一个字段不是字符串类型呢?这个我只能猜它会把其它类型的数据转成字符串类型给你吧。