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

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();
        }
    }
}
SQLiteOpenHelperAndroid提供的一个帮助类,用于管理SQLite数据库的创建和版本更新。其使用方法如下: 1. 创建一个继承自SQLiteOpenHelper的类。 ```java public class MyDatabaseHelper extends SQLiteOpenHelper { // 构造方法 public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } // 数据库第一次创建时调用 @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table user (_id integer primary key autoincrement, name text, age integer)"); } // 数据库版本更新时调用 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("drop table if exists user"); onCreate(db); } } ``` 2. 在需要使用数据库的地方,创建该类的实例,并调用getReadableDatabase()或getWritableDatabase()方法获取可读写的数据库对象。 ```java MyDatabaseHelper dbHelper = new MyDatabaseHelper(context, "mydb", null, 1); SQLiteDatabase db = dbHelper.getReadableDatabase(); ``` 3. 使用SQLiteDatabase对象进行数据库操作。 ```java // 插入数据 ContentValues values = new ContentValues(); values.put("name", "张三"); values.put("age", 20); db.insert("user", null, values); // 查询数据 Cursor cursor = db.query("user", null, null, null, null, null, null); if (cursor.moveToFirst()) { do { String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); } while (cursor.moveToNext()); } cursor.close(); // 更新数据 ContentValues values = new ContentValues(); values.put("age", 21); db.update("user", values, "name=?", new String[]{"张三"}); // 删除数据 db.delete("user", "name=?", new String[]{"张三"}); ``` 4. 关闭数据库。 ```java db.close(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值