- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
2 insert
那么接下来就可以对数据库进行一些 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论