返回介绍

2 insert

发布于 2024-12-23 21:41:49 字数 4694 浏览 0 评论 0 收藏 0

那么接下来就可以对数据库进行一些 CRUD 操作

先分析一下 insert() 和 insertOrThrow() 插入函数:

// 最终会调用 insertWithOnConflict
public long insertWithOnConflict(String table, String nullColumnHack,
    ContentValues initialValues, int conflictAlgorithm) {
  acquireReference();
  try {
    StringBuilder sql = new StringBuilder();
    // 构造 insert SQL 语句

    // 创建 SQLiteStatement 对象,并调用 executeInsert()
    SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
    try {
      return statement.executeInsert();
    } finally {
      statement.close();
    }
  } finally {
    releaseReference();
  }
}

// SQLiteStatement::executeInsert():
public long executeInsert() {
  acquireReference();
  try {
    return getSession().executeForLastInsertedRowId(
        getSql(), getBindArgs(), getConnectionFlags(), null);
  } catch (SQLiteDatabaseCorruptException ex) {
    onCorruption();
    throw ex;
  } finally {
    releaseReference();
  }
}

// getSession() 调用的是 mDatabase.getThreadSession(),获取到 SQLiteSession 对象:

// SQLiteSession::executeForLastInsertedRowId():
public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags,
    CancellationSignal cancellationSignal) {
   // 验证判断

   // 获取一个数据库连接
  acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
  try {
    // 执行 sql 语句
    return mConnection.executeForLastInsertedRowId(sql, bindArgs,
        cancellationSignal); // might throw
  } finally {
    releaseConnection(); // might throw
  }
}

// SQLiteConnection::executeForLastInsertedRowId():
public long executeForLastInsertedRowId(String sql, Object[] bindArgs,
    CancellationSignal cancellationSignal) {
  if (sql == null) {
    throw new IllegalArgumentException("sql must not be null.");
  }

  final int cookie = mRecentOperations.beginOperation("executeForLastInsertedRowId",
      sql, bindArgs);
  try {
    final PreparedStatement statement = acquirePreparedStatement(sql);
    try {
      throwIfStatementForbidden(statement);
      // 绑定数据参数
      bindArguments(statement, bindArgs);
      applyBlockGuardPolicy(statement);
      attachCancellationSignal(cancellationSignal);
      try {
        // 调用 native 执行 sql 语句
        return nativeExecuteForLastInsertedRowId(
            mConnectionPtr, statement.mStatementPtr);
      } finally {
        detachCancellationSignal(cancellationSignal);
      }
    } finally {
      releasePreparedStatement(statement);
    }
  } catch (RuntimeException ex) {
    mRecentOperations.failOperation(cookie, ex);
    throw ex;
  } finally {
    mRecentOperations.endOperation(cookie);
  }
}

这里有几个需要注意一下:

SQLiteSession

private final ThreadLocal<SQLiteSession> mThreadSession = new ThreadLocal<SQLiteSession>() {
  @Override
  protected SQLiteSession initialValue() {
    return createSession();
  }
};

每个线程都拥有自己的 SQLiteSession 对象。多个线程进行数据操作的时候需要注意和处理保持数据的原子性

SQLiteStatement

SQLiteStatement 类代表一个 sql 语句,其父类为 SQLiteProgram,从上面可以看到,insert 操作会先构造出 SQLiteStatement,其构造方法:

SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
    CancellationSignal cancellationSignalForPrepare) {
  mDatabase = db;
  mSql = sql.trim();

  int n = DatabaseUtils.getSqlStatementType(mSql);
  switch (n) {
    case DatabaseUtils.STATEMENT_BEGIN:
    case DatabaseUtils.STATEMENT_COMMIT:
    case DatabaseUtils.STATEMENT_ABORT:
      mReadOnly = false;
      mColumnNames = EMPTY_STRING_ARRAY;
      mNumParameters = 0;
      break;

    default:
      boolean assumeReadOnly = (n == DatabaseUtils.STATEMENT_SELECT);
      SQLiteStatementInfo info = new SQLiteStatementInfo();
      db.getThreadSession().prepare(mSql,
          db.getThreadDefaultConnectionFlags(assumeReadOnly),
          cancellationSignalForPrepare, info);
      mReadOnly = info.readOnly;
      mColumnNames = info.columnNames;
      mNumParameters = info.numParameters;
      break;
  }

  // 参数初始化操作
}

可以看到其会调用 SQLiteSession::prepare() 操作,又是转发到 SQLiteConnection::prepare() 操作,进行 SQL 语法预编译,并会返回行列信息到 SQLiteStatementInfo 中。

再看下插入函数 public long executeForLastInsertedRowId(String sql, Object[] bindArgs, CancellationSignal cancellationSignal) 通过前面的 SQLiteStatement 将 sql 语句和参数组成 sql 并传递进来,通过 PreparedStatement acquirePreparedStatement(String sql) 获取 PreparedStatement 对象,再通过 nativeExecuteForLastInsertedRowId( mConnectionPtr, statement.mStatementPtr) native 方法执行 sql 语句。

在获取 PreparedStatement 的时候,可以看到 PreparedStatement 通过一个 mPreparedStatementCache 来进行缓存操作,具体是一个 LruCache<String, PreparedStatement> 来完成 sql 的缓存

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文