文档章节

SQLite数据库相关(三) SQLiteOpenHelper类

k
 kim366
发布于 2016/05/13 19:36
字数 1815
阅读 4
收藏 0
点赞 2
评论 0

        简介

        前面两篇简单介绍SQLite数据库,包括SQLiteDatabase,实际项目中应该很少使用SQLiteDatabase的方法来打开数据库,而是继承SQLiteOpenHelper开发子类,并通过该子类的getReadableDatabase(),getWritableDatabase()方法打开数据库。

        SQLite是Android提供的一个管理数据库的工具类(工具类这个概念很重要),可用于管理数据库的创建和版本更新。一般扩展他的onCreate(SQLiteDatabase db)和onUpgrate(SQLiteDatabase db, int oldVersion, int newVersion)。这是两个抽象方法。


        构造函数和常用方法

SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

SQLiteOpenHelper( Context context,  String name,  SQLiteDatabase.CursorFactory factory, int version,  DatabaseErrorHandler errorHandler)

synchronized void close()  关闭当前SQLiteOpenHelper对象下的所有数据库对象
String getDatabaseName() 获取构造函数中指定的数据库名对应的数据库对象 
SQLiteDatabase getReadableDatabase() 打开或创建一个只读的数据库对象
SQLiteDatabase getWritableDatabase() 打开一个可读可写的数据库对象
abstract void onCreate( SQLiteDatabase db) 当数据库第一次创建时调用
void onDowngrade( SQLiteDatabase db, int oldVersion, int newVersion) 当数据库降级时调用
void onOpen( SQLiteDatabase db) 数据库打开时调用
abstract void onUpgrade( SQLiteDatabase db, int oldVersion, int newVersion) 当数据库升级时调用

       使用SQLiteOpenHelper时,需要重写oncreate和onUpgrade两个方法

       onCreate(SQLiteDatabae db); 用于初次使用软件时创建数据库表,调用getReadableDatabase()或者getWritableDatabase()生成数据库时,如果数据库不存在,则系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,重写onCreate()时可以生成数据库表结构并添加一些应用使用到的初始化数据。

       onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion); 用于更新软件时更新数据库表结构,方法在数据库的版本发生变化时会被调用,oldVersion和newVersion分别表示旧版本和新版本,当程序创建SQLiteOpenHelper对象时,必须指定一个version参数,该参数就决定了所使用的数据库的版本,也就是说,数据库的版本由程序员控制,只要某次创建SQLiteOpenHelper对象时指定的数据库版本号高于之前的版本号,系统会自动触发onUpgrade(SQLiteDatabae db, int oldVersion, int newVersion)方法,程序就可以根据原版本号和目标版本号进行判断,既可根据版本号进行必要的表结构更新。

        实际上,应用程序在升级表结构的时候完全可能因为现有的数据造成升级失败。后面会专门写一篇分析数据库的升级问题。 

 

       SQLiteOpenHelper源码学习

       先贴上简化后的源码,可以通过原注释和后面的总结一起理解

public abstract class SQLiteOpenHelper {
    /**
     * 创建一个SQLite数据库的帮助类对象用于打开和管理一个数据库
     * 这个方法通常返回非常快速,这个数据库对象并不会在这里直接创建,
     * 知道调用了getWritableDatabase或者getReadableDatabase方法
     */
    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
        this(context, name, factory, version, new DefaultDatabaseErrorHandler());
    }

    /**
     * 和上面的构造函数相同,不过这里多传了一个DatabaseErrorHandler对象,
     * 这个对象用于处理数据库的异常
     */
    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
            DatabaseErrorHandler errorHandler) {
        if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
        if (errorHandler == null) {
            throw new IllegalArgumentException("DatabaseErrorHandler param value can't be null.");
        }

        mContext = context;
        mName = name;
        mFactory = factory;
        mNewVersion = version;
        mErrorHandler = errorHandler;
    }

 
    public String getDatabaseName() {
        return mName;
    }

    /**
     * 1. 创建或打开一个可读可写的数据库,如果是第一次调用,那么数据库会被打开,oncreate,onUpgrade,open都可能调用。
     * 2. 如果打开成功,那么数据库会被缓存,所以你可以在任何时候对其进行读写。
     * 3. 如果不需要再使用这个数据库,那么确保调用close方法将其关闭。
     * 4. 如果发生错误,比如说磁盘已满,或者权限不允许,则正常调用可能会失败,修复问题后可以再次调用。
     * 5. 数据库升级可能会耗费较长时间,所以不应在应用的主线程中调用这个方法,包括ContentProvider。
     */
    public synchronized SQLiteDatabase getWritableDatabase() {
        if (mDatabase != null) {
            if (!mDatabase.isOpen()) {
                // darn! the user closed the database by calling mDatabase.close()
                mDatabase = null;
            } else if (!mDatabase.isReadOnly()) {
                return mDatabase;  // The database is already open for business
            }
        }

        if (mIsInitializing) {
            throw new IllegalStateException("getWritableDatabase called recursively");
        }

        // If we have a read-only database open, someone could be using it
        // (though they shouldn't), which would cause a lock to be held on
        // the file, and our attempts to open the database read-write would
        // fail waiting for the file lock.  To prevent that, we acquire the
        // lock on the read-only database, which shuts out other users.

        boolean success = false;
        SQLiteDatabase db = null;
        if (mDatabase != null) mDatabase.lock();
        try {
            mIsInitializing = true;
            if (mName == null) {
                db = SQLiteDatabase.create(null);
            } else {
                db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler);
            }

            int version = db.getVersion();
            if (version != mNewVersion) {
                db.beginTransaction();
                try {
                    if (version == 0) {
                        onCreate(db);
                    } else {
                        if (version > mNewVersion) {
                            onDowngrade(db, version, mNewVersion);
                        } else {
                            onUpgrade(db, version, mNewVersion);
                        }
                    }
                    db.setVersion(mNewVersion);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }
            }

            onOpen(db);
            success = true;
            return db;
        } finally {
            mIsInitializing = false;
            if (success) {
                if (mDatabase != null) {
                    try { mDatabase.close(); } catch (Exception e) { }
                    mDatabase.unlock();
                }
                mDatabase = db;
            } else {
                if (mDatabase != null) mDatabase.unlock();
                if (db != null) db.close();
            }
        }
    }

    /**
     * 创建或者打开一个数据库,这个数据库对象和调用getWritableDatabase打开的数据库是同一个,除非发生某些意外情况,
     * 在这种情况下,一个只读的数据库对象会被返回,如果问题修复,那么下次调用getWritableDatabase将会成功
     * 这时只读的数据库会被关闭,可读可写的数据库会被返回。
     * 其他的和getWritableDatabase()方法一样。 
     */
    public synchronized SQLiteDatabase getReadableDatabase() {
        if (mDatabase != null) {
            if (!mDatabase.isOpen()) {
                // darn! the user closed the database by calling mDatabase.close()
                mDatabase = null;
            } else {
                return mDatabase;  // The database is already open for business
            }
        }

        if (mIsInitializing) {
            throw new IllegalStateException("getReadableDatabase called recursively");
        }

        try {
            return getWritableDatabase();
        } catch (SQLiteException e) {
            if (mName == null) throw e;  // Can't open a temp database read-only!
            Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e);
        }

        SQLiteDatabase db = null;
        try {
            mIsInitializing = true;
            String path = mContext.getDatabasePath(mName).getPath();
            db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY,
                    mErrorHandler);
            if (db.getVersion() != mNewVersion) {
                throw new SQLiteException("Can't upgrade read-only database from version " +
                        db.getVersion() + " to " + mNewVersion + ": " + path); /** * database. 调用已经打开的数据库,实现类在更新表之前应该检查数据库是否是只读的。 */
            }

            onOpen(db);
            Log.w(TAG, "Opened " + mName + " in read-only mode");
            mDatabase = db;
            return mDatabase;
        } finally {
            mIsInitializing = false;
            if (db != null && db != mDatabase) db.close();
        }
    }


    public synchronized void close() {
        if (mIsInitializing) throw new IllegalStateException("Closed during initialization");

        if (mDatabase != null && mDatabase.isOpen()) {
            mDatabase.close();
            mDatabase = null;
        }
    }


    public abstract void onCreate(SQLiteDatabase db);


    public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);


    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        throw new SQLiteException("Can't downgrade database from version " +
                oldVersion + " to " + newVersion);
    }


    public void onOpen(SQLiteDatabase db) {}
}

        从上面的源代码可知。

       1.  从始至中,SQLiteOpenHelper中只持有一个数据库对象,并且一般情况下,通过getWritableDatabase()和getReadableDatabase()创建或打开时获取到的是同一个SQLiteDatabase对象。

       2.  如果当前数据库是只读的,那么再次调用getWritableDatabase()获取可读可写数据库对象时会重新打开现有对象。

       3.  如果当前不存在数据库对象,并且初始化时没有指定数据库名称,也会创建一个默认数据库。

       4.  如果数据库对象不存在,但是指定了数据库的名称,那么系统会先查看是否有指定数据库,如果有则直接打开,没有则先创建再打开数据库。

       5.  数据库或降级升级时,会根据版本号进行判断,然后把升级和降级的过程作为一个事务进行操作,确保数据安全。

       6.  创建数据库对象的默认版本号为0。

本文转载自:http://blog.csdn.net/oyangyujun/article/details/40711227

共有 人打赏支持
k
粉丝 1
博文 129
码字总数 0
作品 0
朝阳
不会点SQLite,都不好意思说自己是开发的

一、为什么要会点SQLite? SQLite作为一款轻量级的关系型数据库,占用的资源特别少,所以其应用场景也是特别的多。在移动开发中,我们经常会有将数据存储在本地的需求,此时SQLite将是我们最...

silencezwm
07/03
0
0
ANDROID开发之SQLite详解

SQLite简介 Google为Andriod的较大的数据处理提供了SQLite,他在数据存储、管理、维护等各方面都相当出色,功能也非常的强大。SQLite具备下列特点: 1.轻量级 使用 SQLite 只需要带一个动态库...

天下杰论
2013/03/08
0
0
Android开发之SQLite技术详解

  【IT168技术】Google为Andriod的较大的数据处理提供了SQLite,他在数据存储、管理、维护等各方面都相当出色,功能也非常的强大。SQLite具备下列特点:   1.轻量级   使用 SQLite 只需...

庸人谷
2012/11/28
0
0
Android创建和使用数据库详细指南(1)

数据库支持每个应用程序无论大小的生命线,除非你的应用程序只处理简单的数据,那么就需要一个数据库系统存储你的结构化数据,Android使用SQLite数据库,它是一个开源的、支持多操作系统的S...

冯京宝
2011/01/23
0
0
【Android游戏开发十三】(保存游戏数据 [下文])详解SQLite存储方式,并把SQLite的数据库文件存储在SD卡中!!!

李华明Himi 原创,转载务必在明显处注明: 转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/android-game/329.html 很多童鞋说我的代码运行后,点击home或者back后会程序异常,...

迷途d书童
2012/03/19
0
0
Android入门学习_Android SQLite基础

SQLite是Android平台软件开发中会经常用到的数据库产品,作为一款轻型数据库,SQLite的设计目标就是是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中...

cathleencheng
2011/06/03
0
0
android 下 数据持久化

Android实现数据存储技术 数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库存...

andyhe91
2013/09/02
0
0
Android_6.数据存储3_SQLite存储之创建数据库

本文是以Android Studio为开发工具,<> 为学习指导书籍的学习记录 6.4 SQLite数据 SQLite用于存储大量复杂的关系型数据,是内置在Android系统的一种轻量级的关系型数据库,它有速度快,占用资...

橄榄工作室
05/26
0
0
SQLite 在 Android 中的详细使用

声明:本文转载自:http://www.cnblogs.com/weixing/archive/2013/08/02/3232994.html 感谢 “无恨星辰”的知识积累,这对于热爱学习的人来说是一个巨大的帮助..... 1、SQLite简介 SQLite是一...

learn_more
2014/12/12
0
0
android之数据库和Content Provider(一)

安卓SQLite数据库所创建的数据是私有与所创建的应用程序。通过Content Provider给外接提供接口,从而其它的APP可以通过此来访问。 Content Provider基于一个简单的URI地址模型:使用 conten...

Chanimalx
2013/02/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

用 Python 实现打飞机,让子弹飞吧!

所用技术和软件 python 2.7 pygame 1.9.3 pyCharm 准备工作 安装好 pygame 在第一次使用 pygame 的时候,pyCharm 会自动 install pygame。 下载好使用的素材。 技术实现 初始化 pygame 首先要...

猫咪编程
6分钟前
0
0
MySQL的行锁和表锁

简单总结一下行锁和表锁。 行锁 每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 表锁 每次操作锁住整张表。开销小,加锁快;不会出...

to_ln
8分钟前
0
0
Java IO类库之字节数组输入流ByteArrayInputStream

一、ByteArrayInputStream字节数组输入流介绍 ByteArrayInputStream是字节数组输入流,继承自InputStream。它的内部包含一个缓冲区,是一个字节数组,缓冲数组用于保存从流中读取的字节数据,...

老韭菜
10分钟前
0
0
iOS安全应该做哪些事情

1. 尽量使用HTTPS协议。 2. 密码提交的时候,密码使用SHA256加密后传输,MD5等经过哈希碰撞已经可以推算出原文。 3. 密码提交的时候,可以加盐。 4. 密码保存在本地的时候,尽量使用钥匙串保...

HOrange
16分钟前
0
0
react native 注意事项

1. 环境参考官网 android studio 必装 java jdk安装 1.8版本(环境建议自己一步一步配置,切记不要 apt ) 2.有改变编译内容发现 会白屏,然后APP消失,请卸载原来的测试 appinfo (连续两次...

304158
23分钟前
0
0
FOMO游戏代码解析

源代码在此处

怎当她临去时秋波那一转
28分钟前
1
0
EOS智能合约与DApp开发入门

EOS的是Block.One主导研发的一个区块链底层公链系统,它专门为支撑商业去中心化 应用(Decentralized Application)而设计,其代码开源。 比特币被称为区块链1.0,因为它开辟了数字加密货币的...

笔阁
40分钟前
1
0
编译cjson到dll

https://blog.csdn.net/mengzhisuoliu/article/details/52203724 编译完成后 是纯lua实现的json decode 的10倍以上...

梦想游戏人
50分钟前
0
0
JS基础- Date 对象

Date 对象 Date 对象用于处理日期和时间。 创建 Date 对象的语法: var myDate=new Date() 注释:Date 对象会自动把当前日期和时间保存为其初始值。 Date 对象属性 属性 描述 constructor 返...

ZHAO_JH
52分钟前
0
0
Python数据分析numpy(1)

Python开源的科学计算基础库 1.表示N维数组对象ndarray 2.线性代数、傅里叶变换、随机数生成 3.广播函数,整合c++、c 一.数据的维度 1.数据 2.数据维度 3.一维数据 (1)特点 (2)Python中的...

十年磨一剑3344
55分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部