转自: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
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的指针
……
}
|
我们使用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);
}
|
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();
}
|
可以看到,部分是开始事务时相关的方法、部分是准备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
}
|
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
;
}
|
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;
}
……
}
|
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;
}
|
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;
}
|
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();
}
}
}
|
① 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相同的,如果没有相同的获取池中最后一个,如果池子已经空了(此时多个线程同时用着多个连接),新建一个非主连接。
⑥ 具体关系如下