安卓底朝天 —— 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)。如果你的表的第一个字段不是字符串类型呢?这个我只能猜它会把其它类型的数据转成字符串类型给你吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值