热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android应用框架层SQLite源码分析

Android应用框架层SQLite源码分析-概述  Android在应用框架层为开发者提供了SQLite相关操作接口,其归属于android.database.sqlite包底

概述

  Android 在应用框架层为开发者提供了 SQLite 相关操作接口,其归属于android.database.sqlite包底下,主要包含SQLiteProgram, SQLiteDatabase, SQLiteSession, SQLiteConnectionPoolSQLiteConnection等一些类。相比较 SQLite 提供的轻量级接口,应用框架层为开发者封装的 SQLite 抽象层显得更为复杂,但也为开发者屏蔽了更多细节,减小 SQLite 使用难度。

  在设计上,一个 SQLiteDatabase 持有一个 SQLiteConnectionPool, SQLiteConnectionPool 包含 n 个 SQLiteConnection,其根据日志模式的不同,连接池容量也不同。每个线程对于 SQLiteDatabase 的操作通过ThreadLocal创建的 SQLiteSession 来进行管理,而 SQLiteSession 进行操作时需要预先获得一个 SQLiteConnection。如果此时数据库连接池中的连接都被使用,那么会阻塞直到获得可用连接。

SQLiteDatabase

  SQLiteDatabase 提供了一系列管理数据库的方法,通过它我们可以进行增删改查和执行 SQLite 命令语句等操作。其高度封装了SQLiteSession, SQLiteConnectionPoolSQLiteConnection的执行细节,开发者仅需关心上层 API 的使用。

SQLiteDatabase 的打开

  SQLiteDatabase 提供了一系列open*函数,而这些函数的功能是打开数据库连接,区别在于传入的参数不同。

public static SQLiteDatabase openDatabase(@NonNull String path, @NonNull OpenParams openParams);

public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory, @DatabaseOpenFlags int flags);

public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory, @DatabaseOpenFlags int flags, @Nullable DatabaseErrorHandler errorHandler);

public static SQLiteDatabase openOrCreateDatabase(@NonNull String path, @Nullable CursorFactory factory);

public static SQLiteDatabase openOrCreateDatabase(@NonNull String path, @Nullable CursorFactory factory, @Nullable DatabaseErrorHandler errorHandler);

  对于数据库创建、版本升级等管理行为则被封装在SQLiteOpenHelper类中。SQLiteOpenHelper采用延迟初始化的方式来创建或打开数据库,开发者调用getReadableDatabasegetWritableDatabase取得一个SQLiteDatabase实例,而最终都会走到getDatabaseLocked方法。

private SQLiteDatabase getDatabaseLocked(boolean writable) {
    if (mDatabase != null) {
        // 数据库被关闭,此时将 SQLiteDatabase 对象置空,重新打开数据库
        if (!mDatabase.isOpen()) {
            // Darn!  The user closed the database by calling mDatabase.close().
            mDatabase = null;    
        } else if (!writable || !mDatabase.isReadOnly()) {
            // writable 为 false 说明请求只读数据库,满足要求
            // 数据库非只读,支持可读可写,满足要求
            return mDatabase;
        }
    }

    // 防止重复初始化
    if (mIsInitializing) {
        throw new IllegalStateException("getDatabase called recursively");
    }

    SQLiteDatabase db = mDatabase;
    try {
        mIsInitializing = true;

        if (db != null) {
            // 要求可写,但此时数据库以只读方式打开,需要重新以读写方式打开
            if (writable && db.isReadOnly()) {
                db.reopenReadWrite();
            }
        } else if (mName == null) {
            // 数据库名为空,说明要创建内存数据库
            db = SQLiteDatabase.createInMemory(mOpenParamsBuilder.build());
        } else {
            final File filePath = mContext.getDatabasePath(mName);
            // 创建者模式配置打开参数
            SQLiteDatabase.OpenParams params = mOpenParamsBuilder.build();
            try {
                db = SQLiteDatabase.openDatabase(filePath, params);
                // Keep pre-O-MR1 behavior by resetting file permissions to 660
                setFilePermissionsForDb(filePath.getPath());
            // SQLiteDatabase.OpenParams 没有配置 openFlags, 默认以读写方式打开数据库    
            } catch (SQLException ex) {
                // 打开数据库抛出异常,如果要求以可写方式打开,则抛出异常,否则尝试用只读方式打开数据库
                if (writable) {
                    throw ex;
                }
                Log.e(TAG, "Couldn't open " + mName
                        + " for writing (will try read-only):", ex);
                params = params.toBuilder().addOpenFlags(SQLiteDatabase.OPEN_READONLY).build();
                db = SQLiteDatabase.openDatabase(filePath, params);
            }
        }

        // onConfigure 回调,配置数据库相关设置
        onConfigure(db);

        // 获取当前数据库版本
        final int version = db.getVersion();
        // mNewVersion 为自行设置版本,两者不相等时,说明首次创建数据库或者升级或者降级数据库(一般是更改表结构,升级数据库)
        if (version != mNewVersion) {
            if (db.isReadOnly()) {
                throw new SQLiteException("Can't upgrade read-only database from version " +
                        db.getVersion() + " to " + mNewVersion + ": " + mName);
            }

            // 数据库版本小于最小支持版本,删库重建
            if (version > 0 && version  mNewVersion) {
                            onDowngrade(db, version, mNewVersion);
                        } else {
                            onUpgrade(db, version, mNewVersion);
                        }
                    }
                    db.setVersion(mNewVersion);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }
            }
        }

        // onOpen函数被回调
        onOpen(db);

        if (db.isReadOnly()) {
            Log.w(TAG, "Opened " + mName + " in read-only mode");
        }

        mDatabase = db;
        return db;
    } finally {
        mIsInitializing = false;
        if (db != null && db != mDatabase) {
            db.close();
        }
    }
}

  数据库打开相关配置参数设置:

private OpenParams(int openFlags, CursorFactory cursorFactory,
        DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount,
        long idleConnectionTimeout, String journalMode, String syncMode) {
    // 打开模式
    mOpenFlags = openFlags;
    mCursorFactory = cursorFactory;
    // 错误处理器,在抛出 SQLiteDatabaseCorruptionException 时被使用
    mErrorHandler = errorHandler;
    // 默认120kb
    mLookasideSlotSize = lookasideSlotSize;
    // 默认100
    mLookasideSlotCount = lookasideSlotCount;
    // 数据库空闲连接超时时间
    mIdleCOnnectionTimeout= idleConnectionTimeout;
    // 日志模式
    mJournalMode = journalMode;
    // 同步模式
    mSyncMode = syncMode;
}

  SQLiteOpenHelper 调用的SQLiteDatabase#Open*函数最终会打开一个数据库主连接,这个主连接可用来读写,在 SQLiteConnectionPool 部分会进行详细的介绍。

private void open() {
    try {
        try {
            openInner();
        } catch (RuntimeException ex) {
            if (SQLiteDatabaseCorruptException.isCorruptException(ex)) {
                Log.e(TAG, "Database corruption detected in open()", ex);
                onCorruption();
                openInner();
            } else {
                throw ex;
            }
        }
    } catch (SQLiteException ex) {
        Log.e(TAG, "Failed to open database '" + getLabel() + "'.", ex);
        close();
        throw ex;
    }
}

private void openInner() {
    synchronized (mLock) {
        assert mCOnnectionPoolLocked== null;
        // 打开连接池,连接池内部首先打开一个连接,这个连接被定义为数据库主连接
        mCOnnectionPoolLocked= SQLiteConnectionPool.open(mConfigurationLocked);
        mCloseGuardLocked.open("close");
    }

    synchronized (sActiveDatabases) {
        sActiveDatabases.put(this, null);
    }
}

SQLiteClosable

  SQLiteClosable是 Android 应用框架层专门为数据库资源释放设计的类,类似 Java 为 I/O 提供的Closeable标准接口。 在android.database.sqlite包底下的类有着大量应用,确保资源能够及时释放。
  分析源码,其主要提供了两个接口:acquireReference(获取引用计数)和releaseReference(释放引用计数)(注意:这两个的调用总是成对出现)。当引用计数为0时,释放所有相关资源连接,而当引用计数已经为0,如果再次获取引用计数,会抛出IllegalStateException异常。

protected abstract void onAllReferencesReleased();

public void acquireReference() {
    synchronized(this) {
        if (mReferenceCount <= 0) {
            throw new IllegalStateException(
                    "attempt to re-open an already-closed object: " + this);
        }
        mReferenceCount++;
    }
}

public void releaseReference() {
    boolean refCountIsZero = false;
    synchronized(this) {
        refCountIsZero = --mReferenceCount == 0;
    }
    if (refCountIsZero) {
        onAllReferencesReleased();
    }
}

   // TODO 分析 IllegalStateException 异常出现的原因

SQLiteSession

  SQLiteDatabase 的每一个操作都需要通过 SQLiteSession 来完成。每个线程对于一个数据库最多持有一个 SQLiteSession,技术上通过ThreadLocal来保证。这个限制确保一个线程对于给定的数据库同一时刻不能使用多个数据库连接,保证了单进程内数据库使用不会产生死锁。关于事务管理,SQLiteSession 提供 SQLite 三种事务模式的支持,并且支持事务的嵌套。在分析 SQLiteSession 发挥的作用时,我们需要事先了解一下 SQLite 中的锁和事务机制。

SQLite的锁机制

  SQLite采用粗放型的锁。当一个连接要写数据库,所有其它的连接都会被锁住,直到写连接结束了它的事务。SQLite 有一个加锁表,来帮助不同的写数据库都能够在最后一刻再加锁,以保证最大的并发性。SQLite 使用锁逐步上升机制,为了写数据库,连接需要逐级地获得排它锁。SQLite 有5个不同的锁状态,每个数据库连接在同一时刻只能处于其中一个状态。
| 锁状态 | 锁描述 |
| ---------------- | ------------------------------------------------------------ |
| 未加锁-UNLOCKED | 数据库此时不被读取和写入,其他线程或进程可以在它们的锁状态允许的情况下读取或写入数据库。 |
| 共享锁-SHARED | 数据库可以被读取但不能被写入。同一时刻可以有多个线程或进程获得 SHARED 锁,因此同时可以有多个读者。当有一个或多个共享锁时,不允许其他线程或进程写入数据库文件。 |
| 保留锁-RESERVED | RESERVED 锁意味着进程准备写入数据库文件,但它目前只是从文件中读取。一次只能有一个 RESERVED 锁,多个 SHARED 锁可以与一个 RESERVED 锁共存。 RESERVED 与 PENDING 的不同之处在于,当存在 RESERVED 锁时,可以获取新的 SHARED 锁。 |
| 未觉锁-PENDING | PENDING 锁意味着持有锁的进程想要尽快写入数据库,并且只是等待释放当前所有的 SHARED 锁,以便它可以获得 EXCLUSIVE 锁。如果 PENDING 锁处于活动状态,则不允许获得新 SHARED 锁,但允许继续使用现有的 SHARED 锁。 |
| 排它锁-EXCLUSIVE | 写入数据库时需要持有 EXCLUSIVE 锁,同一时刻只允许只有一个 EXCLUSIVE 锁,并且不允许其他锁与它共存。为了最大限度地提高并发性,SQLite 应尽量减少持有独占锁的时间。 |

SQLite的事务类型

  SQLite 支持多个数据库连接同时发起读事务,但写事务同时只能有一个。读事务仅用于读取,写事务则允许读取和写入。读事务由 SELECT 语句启动,写入事务由 CREATE、DELETE、DROP、INSERT 或 UPDATE 等语句启动(统称为“写入语句”)。SQLite 提供了三种不同的事务类型,它们以不同的锁状态启动事务类型,这三种事务类型为:DEFERRED、IMMEDIATE、EXCLUSIVE,默认的事务类型是DEFERRED。事务在 BEGIN 类型中指定:

BEGIN [ DEFERRED | IMMEDIATE | EXCLUSIVE ] TRANSACTION;

BEGIN DEFERRED开启的事务不获取任何锁,直到它需要锁的时候。BEGIN 语句本身不会做什么事情,它开始于 UNLOCK 状态。默认情况下如果仅仅用 BEGIN 开始一个事务,那么事务就是 DEFERRED 的,同时它不会获取任何锁。当对数据库进行第一次读操作时,它会获取 SHARED 锁。同样,当进行第一次写操作时,它会获取 RESERVED 锁。

BEGIN IMMEDIATE 开启的事务会尝试获取 RESERVED 锁。如果成功,BEGIN IMMEDIATE保证没有别的连接可以写数据库。但是别的连接可以对数据库进行读操作。但是 RESERVED 锁会阻止其它连接的BEGIN IMMEDIATE或者BEGIN EXCLUSIVE命令。当其它连接执行上述命令时,会返回SQLITE_BUSY错误。当执行 COMMIT 操作时,如果返回SQLITE_BUSY错误,这意味着还有其它的读事务没有完成,得等它们执行完后才能提交事务。

BEGIN EXCLUSIVE开启的事务会试着获取对数据库的 EXCLUSIVE 锁。这与BEGIN IMMEDIATE类似,但是一旦成功,EXCLUSIVE 事务保证没有其它的连接,所以就可对数据库进行读写操作了。EXCLUSIVE 和 IMMEDIATE 在 WAL 模式下是一样的,但在其他日志模式下,EXCLUSIVE 会阻止其他数据库连接在事务进行时读取数据库。

事务的开启与结束

  上面两个小节介绍了 SQLite 中的锁机制和事务相关概念,现在来看一下 Android 应用框架层是如何进行封装的。
  SQLiteDatabase 提供了几个开启事务的方法,这几个方法主要区别在于传入的参数不同,最终实际调用public void beginTransaction(SQLiteTransactionListener transactionListener, boolean exclusive)方法。在这个方法中尤为重要的是exclusive参数,其决定了开启的事务类型,当为 true 时调用BEGIN EXCLUSIVE; 否则执行BEGIN IMMEDIATE

public void beginTransaction(); // 实际调用 beginTransaction(null, true)

public void beginTransactionNonExclusive(); // 实际调用 beginTransaction(null, false)

public void beginTransactionWithListener(SQLiteTransactionListener transactionListener);    // 实际调用 beginTransaction(transactionListener, true)

public void beginTransactionWithListenerNonExclusive(SQLiteTransactionListener transactionListener));   // 实际调用 beginTransaction(transactionListener, false)

public void beginTransaction(SQLiteTransactionListener transactionListener, boolean exclusive);

SQLiteDatabase 的一系列开启事务方法最终走到SQLiteSession#beginTransactionUnchecked。通过栈的数据结构保存嵌套事务的关系,嵌套事务的执行都在同一个数据库连接当中。如果任何嵌套事务执行失败,那么当最外层事务结束时,包括其所有嵌套事务在内的整个事务将被回滚。

private void beginTransactionUnchecked(int transactionMode,
        SQLiteTransactionListener transactionListener, int connectionFlags,
        CancellationSignal cancellationSignal) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    // 首次执行事务需要先获得一个数据库连接,当有嵌套事务时,最顶层事务获得一次数据库连接,嵌套的事务都使用这个连接对数据库进行操作
    if (mTransactiOnStack== null) {
        acquireConnection(null, connectionFlags, cancellationSignal); // might throw
    }
    try {
        // transactionMode在上层调用 SQLiteDatabase#beginTransaction(SQLiteTransactionListener transactionListener, boolean exclusive)时确定,
        // transactiOnMode= exclusive ? SQLiteSession.TRANSACTION_MODE_EXCLUSIVE :SQLiteSession.TRANSACTION_MODE_IMMEDIATE
        if (mTransactiOnStack== null) {
            // Execute SQL might throw a runtime exception.
            switch (transactionMode) {
                case TRANSACTION_MODE_IMMEDIATE:
                    mConnection.execute("BEGIN IMMEDIATE;", null,
                            cancellationSignal); // might throw
                    break;
                case TRANSACTION_MODE_EXCLUSIVE:
                    mConnection.execute("BEGIN EXCLUSIVE;", null,
                            cancellationSignal); // might throw
                    break;
                default:
                    mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
                    break;
            }
        }

        // Listener might throw a runtime exception.
        if (transactionListener != null) {
            try {
                transactionListener.onBegin(); // might throw
            } catch (RuntimeException ex) {
                if (mTransactiOnStack== null) {
                    mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
                }
                throw ex;
            }
        }

        // 从对象池中复用对象,对象池为链表,每次从队尾取得无用的对象
        Transaction transaction = obtainTransaction(transactionMode, transactionListener);
        // 通过栈的方式存储事务,通过这种形式来对嵌套事务进行支持,栈顶为最内层的事务
        transaction.mParent = mTransactionStack;
        mTransactiOnStack= transaction;
    } finally {
        if (mTransactiOnStack== null) {
            releaseConnection(); // might throw
        }
    }
}

private void endTransactionUnchecked(CancellationSignal cancellationSignal, boolean yielding) {
    if (cancellationSignal != null) {
        cancellationSignal.throwIfCanceled();
    }

    // 获取栈顶的事务
    final Transaction top = mTransactionStack;

    // 事务被标记成功或暂时让步且其下级事务没有失败时认为成功,yielding 为true的case 为 yieldTransaction 的调用
    boolean successful = (top.mMarkedSuccessful || yielding) && !top.mChildFailed;

    RuntimeException listenerException = null;
    final SQLiteTransactionListener listener = top.mListener;
    if (listener != null) {
        try {
            if (successful) {
                listener.onCommit(); // might throw
            } else {
                listener.onRollback(); // might throw
            }
        } catch (RuntimeException ex) {
            listenerException = ex;
            successful = false;
        }
    }

    // 当前栈顶的上一级事务
    mTransactiOnStack= top.mParent;
    // 将无用的事务对象缓存进对象池中
    recycleTransaction(top);

    // 判断事务栈中所有的事务是否执行完成
    if (mTransactionStack != null) {
        if (!successful) {
            // 标记下级事务失败
            mTransactionStack.mChildFailed = true;
        }
    } else {
        // 已经是栈底事务,整个事务只要有一个失败,那么会导致整个事务全部失败
        try {
            // 提交本次事务的修改
            if (successful) {
                mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
            } else {
                // 回滚本次事务的修改
                mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
            }
        } finally {
            releaseConnection(); // might throw
        }
    }

    if (listenerException != null) {
        throw listenerException;
    }
}

  现在我们来看一下beginTransactionUnchecked方法中connectionFlags的确定。由SQLiteDatabase#beginTransaction(SQLiteTransactionListener transactionListener, boolean exclusive)的调用会走入下面的代码,connectionFlags会被标记为需要获取主连接。因此,显式的在代码里面调用beginTransaction方法,即使执行的是读语句也会获取主连接,而同时只能获取一个主连接,因此会导致性能下降。所以如果读语句没有必要,无需显式调用事务开启方法。

@UnsupportedAppUsage
private void beginTransaction(SQLiteTransactionListener transactionListener,
        boolean exclusive) {
    acquireReference();
    try {
        getThreadSession().beginTransaction(
                exclusive ? SQLiteSession.TRANSACTION_MODE_EXCLUSIVE :
                        SQLiteSession.TRANSACTION_MODE_IMMEDIATE,
                transactionListener,
                getThreadDefaultConnectionFlags(false /*readOnly*/), null);
    } finally {
        releaseReference();
    }
}

int getThreadDefaultConnectionFlags(boolean readOnly) {
    int flags = readOnly ? SQLiteConnectionPool.CONNECTION_FLAG_READ_ONLY :
            SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY;
    if (isMainThread()) {
        flags |= SQLiteConnectionPool.CONNECTION_FLAG_INTERACTIVE;
    }
    return flags;
}

SQLiteConnectionPool

  SQLiteConnectionPool 主要用于缓存数据库连接,其包含一个主连接(拥有读写能力)和若干非主连接(拥有只读能力)。

连接池的创建

// 在构造器中确定连接池的大小
private SQLiteConnectionPool(SQLiteDatabaseConfiguration configuration) {
    mCOnfiguration= new SQLiteDatabaseConfiguration(configuration);
    setMaxConnectionPoolSizeLocked();
    // If timeout is set, setup idle connection handler
    // In case of MAX_VALUE - idle connections are never closed
    if (mConfiguration.idleConnectionTimeoutMs != Long.MAX_VALUE) {
        setupIdleConnectionHandler(Looper.getMainLooper(),
                mConfiguration.idleConnectionTimeoutMs);
    }
}

// 对于非内存数据库且开启了 WAL 日志模式的数据库,其池大小由内建的配置决定,一般为4个,取决于不同机型内部的设置,包含1个主连接和 poolSize - 1的非主连接。
// 通过源码也可以看出,连接池大小最小为2
private void setMaxConnectionPoolSizeLocked() {
    if (!mConfiguration.isInMemoryDb()
            && (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) {
        mMaxCOnnectionPoolSize= SQLiteGlobal.getWALConnectionPoolSize();
    } else {
        // We don't actually need to always restrict the connection pool size to 1
        // for non-WAL databases.  There might be reasons to use connection pooling
        // with other journal modes. However, we should always keep pool size of 1 for in-memory
        // databases since every :memory: db is separate from another.
        // For now, enabling connection pooling and using WAL are the same thing in the API.
        mMaxCOnnectionPoolSize= 1;
    }
}

public static int getWALConnectionPoolSize() {
    int value = SystemProperties.getInt("debug.sqlite.wal.poolsize",
            Resources.getSystem().getInteger(
            com.android.internal.R.integer.db_connection_pool_size));
    return Math.max(2, value);
}

// 连接池中主要打开一个数据库主连接
private void open() {
    // Open the primary connection.
    // This might throw if the database is corrupt.
    mAvailablePrimaryCOnnection= openConnectionLocked(mConfiguration,
            true /*primaryConnection*/); // might throw
    // Mark it released so it can be closed after idle timeout
    synchronized (mLock) {
        if (mIdleConnectionHandler != null) {
            mIdleConnectionHandler.connectionReleased(mAvailablePrimaryConnection);
        }
    }

    // Mark the pool as being open for business.
    mIsOpen = true;
    mCloseGuard.open("close");
}

获取连接

  SQLiteSession 对数据库进行操作前需要获得一个数据库连接,其最终调用SQLiteConnectionPool#acquireConnection来取得一个数据库连接。

// SQLiteDatabase#getThreadDefaultConnectionFlags
int getThreadDefaultConnectionFlags(boolean readOnly) {
    int flags = readOnly ? SQLiteConnectionPool.CONNECTION_FLAG_READ_ONLY :
            SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY;
    if (isMainThread()) {
        flags |= SQLiteConnectionPool.CONNECTION_FLAG_INTERACTIVE;
    }
    return flags;
}

// connectionFlags 表示连接类型,其通过 SQLiteDatabase#getThreadDefaultConnectionFlags 确定
public SQLiteConnection acquireConnection(String sql, int connectionFlags,
        CancellationSignal cancellationSignal) {
    SQLiteConnection con = waitForConnection(sql, connectionFlags, cancellationSignal);
    synchronized (mLock) {
        if (mIdleConnectionHandler != null) {
            mIdleConnectionHandler.connectionAcquired(con);
        }
    }
    return con;
}

// 等待可用的连接
private SQLiteConnection waitForConnection(String sql, int connectionFlags,
        CancellationSignal cancellationSignal) {
    // 通过 connectionFlags 确定是否是主连接,当需要写能力时 wantPrimaryConnection 为true
    final boolean wantPrimaryCOnnection=
            (connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0;

    final ConnectionWaiter waiter;
    final int nonce;
    synchronized (mLock) {
        throwIfClosedLocked();

        // Abort if canceled.
        if (cancellationSignal != null) {
            cancellationSignal.throwIfCanceled();
        }

        // Try to acquire a connection.
        SQLiteConnection cOnnection= null;
        // 需要非主连接,尝试从可用连接池中获取一个连接,如果没有达到池上限,创建一个数据库连接
        if (!wantPrimaryConnection) {
            cOnnection= tryAcquireNonPrimaryConnectionLocked(
                    sql, connectionFlags); // might throw
        }
        // 没有可用的非主连接或需要主连接,尝试获取主连接
        if (cOnnection== null) {
            cOnnection= tryAcquirePrimaryConnectionLocked(connectionFlags); // might throw
        }
        if (connection != null) {
            return connection;
        }

        // 没有可用的主连接,根据连接优先级插入队列,如果是在主线程获取连接,则为高优先级
        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;
    }

    // Set up the cancellation listener.
    if (cancellationSignal != null) {
        cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
            @Override
            public void onCancel() {
                synchronized (mLock) {
                    if (waiter.mNOnce== nonce) {
                        cancelConnectionWaiterLocked(waiter);
                    }
                }
            }
        });
    }
    try {
        // 默认30s
        long busyTimeoutMillis = CONNECTION_POOL_BUSY_MILLIS;
        long nextBusyTimeoutTime = waiter.mStartTime + busyTimeoutMillis;
        for (;;) {
            // 检测处于泄漏的连接并使用它
            if (mConnectionLeaked.compareAndSet(true, false)) {
                synchronized (mLock) {
                    // 唤醒等待
                    wakeConnectionWaitersLocked();
                }
            }

            // 使当前线程进入休眠,最长30s
            LockSupport.parkNanos(this, busyTimeoutMillis * 1000000L);

            // Clear the interrupted flag, just in case.
            Thread.interrupted();

            // Check whether we are done waiting yet.
            synchronized (mLock) {
                throwIfClosedLocked();

                final SQLiteConnection cOnnection= waiter.mAssignedConnection;
                final RuntimeException ex = waiter.mException;
                // 释放的可用连接是否给到当前这个等待的 waiter,如果是则直接返回
                if (connection != null || ex != null) {
                    recycleConnectionWaiterLocked(waiter);
                    if (connection != null) {
                        return connection;
                    }
                    throw ex; // rethrow!
                }

                // 没有获得可用连接,从新调整休眠时间
                final long now = SystemClock.uptimeMillis();
                if (now 

释放连接

public void releaseConnection(SQLiteConnection connection) {
    synchronized (mLock) {
        if (mIdleConnectionHandler != null) {
            mIdleConnectionHandler.connectionReleased(connection);
        }
        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();
        }
    }
}

参考链接

  • SQLite Locking
  • SQLite Transaction
  • Writing-Ahead Logging

推荐阅读
  • 本文详细介绍了PHP中的几种超全局变量,包括$GLOBAL、$_SERVER、$_POST、$_GET等,并探讨了AJAX的工作原理及其优缺点。通过具体示例,帮助读者更好地理解和应用这些技术。 ... [详细]
  • 这个报错出现在userDao里面,sessionfactory没有注入。解决办法:spring整合Hibernate使用test测试时要把spring.xml和spring-hib ... [详细]
  • Android和iOS的数据库都是用SQLite来实现.一,SQLite数据库简介:轻量级:SQLite数据库是一个轻量级的数据库,适用于少量数据的CURD;文件本质:SQL ... [详细]
  • Hibernate入门指南:单表数据库操作详解
    本文介绍了Hibernate作为全面的ORM框架的基础知识,并详细讲解了在MyEclipse环境中配置Hibernate以及进行基本的数据库单表操作的方法,包括增删改查等常见操作。 ... [详细]
  • Windows 系统中 Flutter 与 IntelliJ IDEA 的环境配置指南
    本指南详细介绍了如何在 Windows 操作系统上设置 Flutter 开发环境,并集成至 IntelliJ IDEA 中,适合初学者及专业人士参考。 ... [详细]
  • 深入解析 Android 中的 ActivityGroup 实现
    本文详细探讨了如何在 Android 应用中使用 ActivityGroup 来实现类似微博客户端主界面的效果,并分析了 TabActivity 的局限性,推荐使用更为灵活的 ActivityGroup 方案。 ... [详细]
  • 利用Selenium框架解决SSO单点登录接口无法返回Token的问题
    针对接口自动化测试中遇到的SSO单点登录系统不支持通过API接口返回Token的问题,本文提供了一种解决方案,即通过UI自动化工具Selenium模拟用户登录过程,从浏览器的localStorage或sessionStorage中提取Token。 ... [详细]
  • 本文详细介绍如何在Spring Boot项目中集成和使用JPA,涵盖JPA的基本概念、Spring Data JPA的功能以及具体的操作步骤,帮助开发者快速掌握这一强大的持久化技术。 ... [详细]
  • 本文探讨了SQLAlchemy ORM框架中如何利用外键和关系(relationship)来建立表间联系,简化复杂的查询操作。通过示例代码详细解释了relationship的定义、使用方法及其与外键的相互作用。 ... [详细]
  • 构建高性能Feed流系统的设计指南
    随着移动互联网的发展,Feed流系统成为了众多社交应用的核心组成部分。本文将深入探讨如何设计一个高效、稳定的Feed流系统,涵盖从基础架构到高级特性的各个方面。 ... [详细]
  • 本文详细解析 Skynet 的启动流程,包括配置文件的读取、环境变量的设置、主要线程的启动(如 timer、socket、monitor 和 worker 线程),以及消息队列的实现机制。 ... [详细]
  • 本文由chszs撰写,详细介绍了Apache Mina框架的核心开发流程及自定义协议处理方法。文章涵盖从创建IoService实例到协议编解码的具体步骤,适合希望深入了解Mina框架应用的开发者。 ... [详细]
  • Hibernate全自动全映射ORM框架,旨在消除sql,是一个持久层的ORM框架1)、基础概念DAO(DataAccessorOb ... [详细]
  • Iamcopyingapre-existingdatabasetodatadatapackagenamedatabasesusingcodelearnedfromusi ... [详细]
  • 优化 Kotlin 中的 Android Retrofit 和 RxJava 使用
    本文介绍如何在 Kotlin 语言中进一步优化 Android Retrofit 和 RxJava 的使用,通过动态代理简化线程管理,并提供更简洁的代码实现。 ... [详细]
author-avatar
手机用户2602922857
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有