转自:http://www.2cto.com/kf/201402/276805.html


Android中使用sqlite,使用最多的类莫过于SQLiteOpenHelper及SQLiteDatabased两个类。使用最多的操作莫过于创建打开数据库、操作数据两种操作,后者最长用的是insert delete update、query两种操作。其中,query即select操作又牵扯到cursor等。

上述操作主要涉及SQLiteDatabase SQLiteSession SQLiteConnectionPool SQLiteConnection四个大类。本文将对Android操作sqlite的内部流程做简要分析。

1、主要类成员变量

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public final class SQLiteDatabase extends SQLiteClosable { private static WeakHashMap<sqlitedatabase, object= "" > sActiveDatabases = new WeakHashMap<sqlitedatabase, object= "" >(); // 存储所有打开的数据库的引用 private final ThreadLocal<sqlitesession> mThreadSession = new ThreadLocal<sqlitesession>() { @Override protected SQLiteSession initialValue() { // 每个线程有自己的一份mThreadSeesion return createSession(); } }; private final CursorFactory mCursorFactory; // Cursor工厂类,为了自定义Cursor private final SQLiteDatabaseConfiguration mConfigurationLocked; // 数据库的配置 private SQLiteConnectionPool mConnectionPoolLocked; // 数据库连接池 …… }</sqlitesession></sqlitesession></sqlitedatabase,></sqlitedatabase,>
?
1 2 3 4 5 6 7 8 9 public final class SQLiteSession { private final SQLiteConnectionPool mConnectionPool; // 连接池 private SQLiteConnection mConnection; // 连接 private int mConnectionFlags; private int mConnectionUseCount; private Transaction mTransactionPool; // 事务池 private Transaction mTransactionStack; // 事务栈 …… }
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public final class SQLiteConnectionPool implements Closeable { private final SQLiteDatabaseConfiguration mConfiguration; private int mMaxConnectionPoolSize; private boolean mIsOpen; private int mNextConnectionId; private ConnectionWaiter mConnectionWaiterPool; // 连接等待池 其实是由 等待的连接 组成的链 private ConnectionWaiter mConnectionWaiterQueue; // 连接等待队列 private final ArrayList<sqliteconnection> mAvailableNonPrimaryConnections = new ArrayList<sqliteconnection>(); //强引用,非主连接 private SQLiteConnection mAvailablePrimaryConnection; // 主连接 只有一个 private final WeakHashMap<sqliteconnection, acquiredconnectionstatus= "" > mAcquiredConnections = new WeakHashMap<sqliteconnection, acquiredconnectionstatus= "" >(); //弱引用,已取得的连接 …… } </sqliteconnection,></sqliteconnection,></sqliteconnection></sqliteconnection>
?
1 2 3 4 5 6 7 8 9 10 11 public final class SQLiteConnection implements CancellationSignal.OnCancelListener { private final SQLiteConnectionPool mPool; private final SQLiteDatabaseConfiguration mConfiguration; private final int mConnectionId; private final boolean mIsPrimaryConnection; private final boolean mIsReadOnlyConnection; private final PreparedStatementCache mPreparedStatementCache; //stmt的缓存 强引用 private PreparedStatement mPreparedStatementPool; private int mConnectionPtr; // native层SQLiteConnection的指针 …… }

2、打开数据库时的调用情况

我们使用SQLiteOpenHelper时:

新建一个帮助类,getReadableDatabase或getWritableDatabase时,到②的第二条新打开

如果已经有了帮助类并且使用过,如果已经手动mDatabase.close过,到②的第二条新打开

getReadableDatabase时,无论上次使用是getReadableDatabase还是getWritableDatabase,会直接返回mDatabase,

getWritableDatabase时,如果上次是getWritableDatabase依然直接返回mDataBase,如果上次是getReadableDatabase,到②的第一条以读写模式打开。


如果已经有了帮助类,如果需要写入但现在是只读,即上次是getReadableDatabas这次是getWritableDatabase,则以读写模式重新打开db.reopenreadwrite

否则,如果getReadableDatabase,通过SQLiteDatabase.openDatabase打开只读数据库;如果getWritableDatabase,通过mContext.openOrCreateDatabase,最终仍通过SQLiteDatabase.openDatabase打开,此时flag已经变作CREATE_IF_NECESSARY。

到SQLiteDatabase中看下

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags, DatabaseErrorHandler errorHandler) { SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler); db.open(); // open会调用openInner 省略 return db; } private void openInner() { synchronized (mLock) { assert mConnectionPoolLocked == null ; mConnectionPoolLocked = SQLiteConnectionPool.open(mConfigurationLocked); mCloseGuardLocked.open( "close" ); } synchronized (sActiveDatabases) { sActiveDatabases.put( this , null ); // 放入sActiveDatabases } }


SQLiteDatabase 持有自己的连接池,在open时获取到,在SQLiteConnectionPool中

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static SQLiteConnectionPool open(SQLiteDatabaseConfiguration configuration) { SQLiteConnectionPool pool = new SQLiteConnectionPool(configuration); pool.open(); return pool; } private void open() { mAvailablePrimaryConnection = openConnectionLocked(mConfiguration, true /*primaryConnection*/ ); // 打开连接池 其实是打开一个主连接 mIsOpen = true ; mCloseGuard.open( "close" ); } private SQLiteConnection openConnectionLocked(SQLiteDatabaseConfiguration configuration, boolean primaryConnection) { final int connectionId = mNextConnectionId++; return SQLiteConnection.open( this , configuration, // 通过调用connection.open() connectionId, primaryConnection); }

SQLiteConnection调用的方法就是native层面了,open方法也比较简单。

?
1 2 3 4 5 6 7 8 9 10 11 12 private void open() { //--- !!! nativeOpen 并设置相应参数 mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags, mConfiguration.label, SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME); setPageSize(); setForeignKeyModeFromConfiguration(); setWalModeFromConfiguration(); setJournalSizeLimit(); setAutoCheckpointInterval(); setLocaleFromConfiguration(); }

流程很简单,令人疑惑的是SQLiteConnectionPool在这里的作用。更令人疑惑的是连接池此时呈现出来的仅仅是一个主连接。
SQLiteConnectionPool中最为重要的成员是acquireConnection,下图表示了调用该成员的类及方法

可以看到,部分是开始事务时相关的方法、部分是准备statement时用到、部分是query时cursor用到。还有部分是与带返回结果的及不带返回结果的sql相关的操作,但这部分没有外部调用,也没有内部调用。其实不是的,最后一部分是为常用的insert delete update 等,具体如下。

<喎�"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPGgyPjOhomV4ZWNTUUy1xLX308PB97PMPC9oMj4K0tRTUUxpdGVEYXRhYmFzZS5leGVjU1FMzqrA/Txicj4KPHA+PC9wPgo8cD48L3A+CjxwcmUgY2xhc3M9"brush:java;"> public void execSQL(String sql) throws SQLException { //执行单条 无返回值 非select的sql executeSql(sql, null); } private int executeSql(String sql, Object[] bindArgs) throws SQLException { …… SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs); // 获取statement try { return statement.executeUpdateDelete(); } finally { statement.close(); } } public int executeUpdateDelete() { acquireReference(); try { return getSession().executeForChangedRowCount( // getSession在此出现 getSql(), getBindArgs(), getConnectionFlags(), null); } catch (SQLiteDatabaseCorruptException ex) { onCorruption(); throw ex; } finally { releaseReference(); } }

?
1 2 3 4 5 6 7 protected final SQLiteSession getSession() { // SQLiteProgram中 return mDatabase.getThreadSession(); } SQLiteSession getThreadSession() { // SQLiteDatabase中 return mThreadSession.get(); // 和第1部分对应起来了 每个线程有自己的Session }

继续查看 getSession().executeForChangedRowCount

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // SQLiteSession中 public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags, CancellationSignal cancellationSignal) { …… acquireConnection(sql, connectionFlags, cancellationSignal); // 获取连接 try { return mConnection.executeForChangedRowCount(sql, bindArgs, // 通过connection执行 cancellationSignal); } finally { releaseConnection(); } } // SQLiteSession中 private void acquireConnection(String sql, int connectionFlags, CancellationSignal cancellationSignal) { if (mConnection == null ) { assert mConnectionUseCount == 0 ; mConnection = mConnectionPool.acquireConnection(sql, connectionFlags, // 连接池中获取连接 cancellationSignal); // might throw mConnectionFlags = connectionFlags; } mConnectionUseCount += 1 ; }

总算找到SQLiteConnectionPool.acquireConnection了

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 // SQLiteConnectionPool中 public SQLiteConnection acquireConnection(String sql, int connectionFlags, CancellationSignal cancellationSignal) { return waitForConnection(sql, connectionFlags, cancellationSignal); } private SQLiteConnection waitForConnection(String sql, int connectionFlags, CancellationSignal cancellationSignal) { final boolean wantPrimaryConnection = // 是否需要主连接,通过Flag得到 (connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0 ; final ConnectionWaiter waiter; synchronized (mLock) { SQLiteConnection connection = null ; if (!wantPrimaryConnection) { // 尝试获取非主连接 connection = tryAcquireNonPrimaryConnectionLocked( sql, connectionFlags); } if (connection == null ) { //--- 尝试获取主连接 connection = tryAcquirePrimaryConnectionLocked(connectionFlags); } if (connection != null ) { return connection; } // 若得不到连接,生成一个waiter final int priority = getPriority(connectionFlags); final long startTime = SystemClock.uptimeMillis(); waiter = obtainConnectionWaiterLocked(Thread.currentThread(), startTime, priority, wantPrimaryConnection, sql, connectionFlags); // 根据优先级插入 队列 ConnectionWaiter predecessor = null ; ConnectionWaiter successor = mConnectionWaiterQueue; while (successor != null ) { if (priority > successor.mPriority) { waiter.mNext = successor; break ; } predecessor = successor; successor = successor.mNext; } if (predecessor != null ) { predecessor.mNext = waiter; } else { mConnectionWaiterQueue = waiter; } nonce = waiter.mNonce; } …… }

这里根据connectionFlags判定是否要获得主连接,如第2步分析数据库open时,就是主连接

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private SQLiteConnection tryAcquirePrimaryConnectionLocked( int connectionFlags) { // 主连接可获取 直接返回 SQLiteConnection connection = mAvailablePrimaryConnection; if (connection != null ) { mAvailablePrimaryConnection = null ; finishAcquireConnectionLocked(connection, connectionFlags); return connection; } // 主连接存在并且刚刚获取过,则返回空 for (SQLiteConnection acquiredConnection : mAcquiredConnections.keySet()) { if (acquiredConnection.isPrimaryConnection()) { return null ; } } // 主连接不存在 新建 只可能在第一次访问时发生 connection = openConnectionLocked(mConfiguration, true /*primaryConnection*/ ); finishAcquireConnectionLocked(connection, connectionFlags); return connection; }

其他时候,例如本节的update,将依靠statement的属性,由其一个成员变量mReadOnly来表示,实际由sql转换为stmt即prepare时确定。例如begin commit 命令将是false。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 private SQLiteConnection tryAcquireNonPrimaryConnectionLocked( String sql, int connectionFlags) { // 尝试获取非主连接队列中的下一个连接 SQLiteConnection connection; final int availableCount = mAvailableNonPrimaryConnections.size(); if (availableCount > 1 && sql != null ) { // 如果sql!=null 优先使用缓存中含有相同sql语句的connection for ( int i = 0 ; i < availableCount; i++) { connection = mAvailableNonPrimaryConnections.get(i); if (connection.isPreparedStatementInCache(sql)) { mAvailableNonPrimaryConnections.remove(i); finishAcquireConnectionLocked(connection, connectionFlags); // might throw return connection; } } } if (availableCount > 0 ) { // 否则获取下一个连接,其实是pool最后一个 connection = mAvailableNonPrimaryConnections.remove(availableCount - 1 ); finishAcquireConnectionLocked(connection, connectionFlags); // might throw return connection; } //--- 若有需要即池中无连接时,扩展连接池, int openConnections = mAcquiredConnections.size(); if (mAvailablePrimaryConnection != null ) { openConnections += 1 ; } if (openConnections >= mMaxConnectionPoolSize) { return null ; } connection = openConnectionLocked(mConfiguration, // 新打开一个非主连接,真正连接到nativeOpen false /*primaryConnection*/ ); finishAcquireConnectionLocked(connection, connectionFlags); // 会将新建立的connection放入mAcquiredConnections return connection; }

那么mAvailableNonPrimaryConnections中的连接是怎么来的呢?
但凡使用acquireConnection后,必须使用releaseConnection

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 // SQLiteSession中 private void releaseConnection() { assert mConnection != null ; assert mConnectionUseCount > 0 ; if (--mConnectionUseCount == 0 ) { try { mConnectionPool.releaseConnection(mConnection); // might throw } finally { mConnection = null ; } } } // SQLiteConnectionPool中 public void releaseConnection(SQLiteConnection connection) { synchronized (mLock) { AcquiredConnectionStatus status = mAcquiredConnections.remove(connection); if (status == null ) { throw new IllegalStateException( "Cannot perform this operation " + "because the specified connection was not acquired " + "from this pool or has already been released." ); } if (!mIsOpen) { closeConnectionAndLogExceptionsLocked(connection); } else if (connection.isPrimaryConnection()) { if (recycleConnectionLocked(connection, status)) { assert mAvailablePrimaryConnection == null ; mAvailablePrimaryConnection = connection; // 放入主连接 } wakeConnectionWaitersLocked(); } else if (mAvailableNonPrimaryConnections.size() >= mMaxConnectionPoolSize - 1 ) { closeConnectionAndLogExceptionsLocked(connection); } else { if (recycleConnectionLocked(connection, status)) { mAvailableNonPrimaryConnections.add(connection); 放入非主连接 } wakeConnectionWaitersLocked(); } } }

一个connection或者属于SQLiteConnectionPool或者属于SQLiteSession
SQLiteSession通过acquire从SQLiteConnectionPool获取connection,通过release将其返还。

4、总结

①AndroidSQLite中,多数操作需经过 SQLiteDatabase -> SQLiteSession -> SQLiteConnectionPool -> SQLiteConnection

② SQLiteOpenHelper类能够帮助实现一个实例里最多只有一个SQLiteDatabase对象,无论经过几次getReadableDatabase getWritableDatabase,是否经过了db.close()。

③ SQLiteDatabase.openDatabase的过程是构建SQLiteDatabase对象的过程,实质是构建SQLiteDatabase的成员变量SQLiteConnectionPool的过程,该过程是一个获取primaryConnection的过程。

④ 每个线程有自己的SQLiteSession且只有一个,每个SQLiteSession在某一时刻最多只有一个SQLiteConnection(需要时从连接池获取,用完返还),保证了一个线程在某一时刻只有一个SQLiteConnection连接到某一SQLiteDatabase。事务同样通过Session来实现,故线程之间的事务是独立的。

⑤ SQLiteConnectionPool掌管某个SQLiteDatabase的连接池。确保PrimaryConnection只有一个,如果空闲则将其返回,如果正被其他session使用则返回空,如果没有则新建。对于非PrimaryConnection,将会在连接池中优先选取stmt相同的,如果没有相同的获取池中最后一个,如果池子已经空了(此时多个线程同时用着多个连接),新建一个非主连接。

⑥ 具体关系如下




更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. android客户端使用ssl连接mqtt服务器(单向认证)
  3. Android开发经验之获取画在画布上的字符串长度、宽度(所占像素宽
  4. 在 WebView 中获取当前网络状态(Wi-Fi 3G 4G)
  5. cocos2dx实现获得设备的网络连接状态
  6. Android(安卓)Bitmap与Canvas
  7. Android(安卓)Studio一个连接SQLite数据库的登录注册实现
  8. android task与back stack 开发文档翻译 - 1
  9. Android开发之获取网络类型(WIFI、2G、3G、4G)和运营商名称

随机推荐

  1. Android学习笔记十五之TableLayout表格布
  2. N 个 Android(安卓)项目源码
  3. Android TextView 设置背景半透明,文字不
  4. Android(安卓)运行时给动态加载的图标按
  5. Android 使用 Application
  6. Android(六)通知、样式、主题、HTML
  7. 四大组件之服务(Service)
  8. DB Usage Complete / ADB 用法大全(转自g
  9. Android调用平台功能具体技巧分享
  10. [Android1.6]动态添加View的问题