您的位置:首页 > 数据库 > SQL

SQLiteOpenHelper的getReadableDatabase()和getWritableDatabase()方法理解灵感

2016-11-24 22:37 567 查看
getReadableDatabase()和getWritableDatabase()

两个方法都是用来获取数据库对象的,那么它们有什么不同呢?

首先说一下,它们的 相同点和不同点

相同点

1, 获得一个数据库的对象实例

2, 如果数据库没有创建,那么就创建一个,并且创建完数据库之后打开数据库,返回一个数据库对象

3, 如果数据库已经创建,那么就打开数据库,并且返回一个数据库对象

不同点

getReadableDatabase()

1, 先以读写方式打开数据库, 获得一个读写数据库对象

2, 如果数据库的磁盘空间满了,就会打开失败。当打开失败后会继续尝试以只读方式打开数据库, 获得一个只读的数据库对象

3, 如果该问题成功解决, 则只读数据库对象就会关闭,然后 获得一个可读写的数据库对象

getWritableDatabase()

1, 以读写方式打开数据库,获得一个读写数据库对象

2, 一旦数据库的磁盘空间满了,数据库就只能读而不能写,最后 抛出异常,程序停止运行

然后是它们的 执行过程

既然要说 SQLiteOpenHelpergetReadableDatabase()和getWritableDatabase() 的执行过程

那么先将 SQLiteOpenHelper 的构造方法执行过程说一下, 因为要用

由于 SQLiteOpenHelper 是一个抽象类,所以要用一个类继承它

继承它的类,必须实现它的构造方法,它一共有 两个有参构造方法, 没有无参构造方法

public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
// 调用参数多的那个构造方法
this(context, name, factory, version, null);
}


public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
DatabaseErrorHandler errorHandler) {
// 先判断一个版本是否大于1,如果不是,那么抛出异常 IllegalArgumentException
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
// 将传递过来的 上下文环境 传递给 当前类的mContext成员对象
mContext = context;
// 将传递过来的 数据库名称 传递给 当前类的mName成员对象
mName = name;
// 将传递过来的 CursorFactory游标工厂 传递给 当前类的mFactory成员对象
// ps : 如果我们传递过来的 CursorFactory 游标工厂为 null 的话,那么将使用默认的 CursorFactory游标工厂
mFactory = factory;
// 将传递过来的 数据库版本号 传递给 当前类的mNewVersion成员对象
mNewVersion = version;
// 将传递过来的 DatabaseErrorHandler对象 传递给 当前类的mErrorHandler成员对象
mErrorHandler = errorHandler;
}


好了,现在可以介绍方法的执行过程了

getReadableDatabase()

1, 调用 SQLiteOpenHelpergetDatabaseLocked(boolean writable) 方法

并且传递一个 falsegetDatabaseLocked(boolean writable) 方法

public SQLiteDatabase getWritableDatabase() {
// 锁定当前类,用来线程间的同步,这里不详解
synchronized (this) {
return getDatabaseLocked(false);
}
}


getWritableDatabase()

1, 调用 SQLiteOpenHelpergetDatabaseLocked(boolean writable) 方法

并且传递一个 truegetDatabaseLocked(boolean writable) 方法

public SQLiteDatabase getWritableDatabase() {
// 锁定当前类,用来线程间的同步,这里不详解
synchronized (this) {
return getDatabaseLocked(true);
}
}


接下来, 由于它们的执行方法基本相同,所以介绍其中一个就可以了

SQLiteOpenHelpergetDatabaseLocked(boolean writable) 方法 相同的 执行过程

private SQLiteDatabase getDatabaseLocked(boolean writable) {
// 如果 mDatabase 数据库不是空的
// ps : mDatabase 是一个 SQLiteDatabase 的对象
if (mDatabase != null) {
// 如果mDatabase数据库是打开的状态的取反状态(就是数据库关闭状态)
if (!mDatabase.isOpen()) {
// Darn! The user closed the database by calling mDatabase.close().
// 翻译 : 该死的!用户通过调用mDatabase.close()关闭了数据库
mDatabase = null;
} else if (!writable || !mDatabase.isReadOnly()) {
// The database is already open for business.
// 翻译 : 该数据库的业务已经打开了(说明直接把数据库对象返回)
return mDatabase;
}
}
// 如果mIsInitializing是true,那么抛出一个 IllegalStateException 异常
// ps : IsInitializing 我猜测应该意思是: 是否初始化
if (mIsInitializing) {
throw new IllegalStateException("getDatabase called recursively");
}
// 将 mDatabase 对象的值,给 SQLiteDatabase 的 db 对象
SQLiteDatabase db = mDatabase;
try {
// 将是否初始化的变量修改为 true ,说明我已经开始初始化了
mIsInitializing = true;
// 如果数据库 db 对象不等于 null
if (db != null) {
// 判断一下 writable 是否为 true 还有 数据库是不是只读
if (writable && db.isReadOnly()) {
// 将数据库重新打开变成可读写
db.reopenReadWrite();
}
// 如果数据库名称为 null
} else if (mName == null) {
// 创建一个数据库对象
db = SQLiteDatabase.create(null);
// 如果上面的判断都不成立,那么执行else里面的逻辑
} else {
try {
// 如果DEBUG_STRICT_READONLY(调试严格只读) 为 true 并且 writable 为 false,那么开始执行
if (DEBUG_STRICT_READONLY && !writable) {
// 根据数据库名称 获取 数据库的存储路径
final String path = mContext.getDatabasePath(mName).getPath();
// 通过数据库路径 获取得到一个 SQLiteDatabase 数据库对象
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
// 如果上面的条件不成立,那么执行 else 里面的逻辑
} else {
// 通过 数据库名称 得到 一个可以读写的 数据库对象
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
mFactory, mErrorHandler);
}
// 异常处理逻辑
} catch (SQLiteException ex) {
// 如果 writable 为 true 的话直接 抛出异常
if (writable) {
throw ex;
}
// 打印日志提醒
Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", ex);
// 根据数据库名称 获取 数据库路径
final String path = mContext.getDatabasePath(mName).getPath();
// 获得一个 只读 数据库对象
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
}
}

// 将处理好的 数据库对象 交给 onConfigure(SQLiteDatabase db) 方法 处理
// ps : 好像是最底层的核心源码,访问不了,猜测用来 创建 本地数据库文件的
onConfigure(db);

// 获取 数据库对象 的版本号
final int version = db.getVersion();
// 如果 版本号 与 新版本号不一样,那么就 执行里面的逻辑
if (version != mNewVersion) {
// 判断一下数据库是不是只读的
if (db.isReadOnly()) {
// 抛出一个 SQLiteException 异常
throw new SQLiteException("Can't upgrade read-only database from version " +
db.getVersion() + " to " + mNewVersion + ": " + mName);
}
// 开启数据库的 事物
db.beginTransaction();
try {
// 如果version为0,那么就代表数据库是第一次创建
if (version == 0) {
// 将我们处理后的 数据库对象 传递给我们重写的 onCreate(SQLiteDatabase db)方法
// ps : 看到这里的你,是不是 突然 明悟了 onCreate(SQLiteDatabase db)方法 原来是这样调用的
onCreate(db);
} else {
// 如果 当前数据库版本号 大于 传递过来的新数据库版本号
if (version > mNewVersion) {
// 执行数据库的降级方法
// ps : Android 4.0 以上的版本执行 onDowngrade 方法会抛异常,谷歌不允许
onDowngrade(db, version, mNewVersion);
// 上面的条件都不满足
// ps : 剩下了 当前数据库版本号 小于 传递过来的新数据库版本号
} else {
// 执行数据库的 升级方法
// ps : 看到这里的你,是不是
// 突然 明悟了 onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 方法
// 原来是这样调用的
onUpgrade(db, version, mNewVersion);
}
}

// 给数据库设置版本号
db.setVersion(mNewVersion);

// 将当前 数据库事物 标记为成功
db.setTransactionSuccessful();
} finally {
// 结束 数据库的事物
db.endTransaction();
}
}

// 将数据库对象传递给 重写的onOpen(SQLiteDatabase db)方法
onOpen(db);

// 如果数据库是只读的,打印一个日志
if (db.isReadOnly()) {
Log.w(TAG, "Opened " + mName + " in read-only mode");
}

// 将处理好的最终 db数据库对象 赋值给 mDatabase
mDatabase = db;

// 最后返回我们想要得到的 数据库对象
return db;

// return 之后,执行finally 里面的逻辑
// ps : return之后 不会对 finally里面的逻辑 有影响,照常运行,不要问什么,自己测试一下就知道了 (已测试)
} finally {
// 将 mIsInitializing(初始化标识) 设置为 false
mIsInitializing = false;
// 如果 db数据库对象 不为null 和 db数据库对象 不等于 mDatabase数据库对象
if (db != null && db != mDatabase) {
// 将db数据库关闭
db.close();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息