Android SQLiteDatabase SQLiteSession SQLiteConnectionPool SQLiteConnection关系

转自: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、总结

① Android SQLite中,多数操作需经过 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相同的,如果没有相同的获取池中最后一个,如果池子已经空了(此时多个线程同时用着多个连接),新建一个非主连接。

⑥ 具体关系如下




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值