前言

SQLite数据库一款轻量级关系数据库,轻量型、跨平台、多语言接口、安全、支持事务处理,而且运算速度快,占用资源少。Android数据持久化存储的内部存储主要存在在内部存储设备上,恰恰Android内部设备存储空间往往是有限的,如果不有效的管理内部存储空间,很有可能导致手机直接崩溃无法使用。而且SQLite轻量级及相关有点正好符合了Android本身的特性。其实Android另外两个存储方式:文件存储和SharePreferences存储中的SharePreferences存储就属于轻量型存储机智。而对于文件存储要去也是尽量存储到外部存储设备中。因此SQLite本身的优点特别适合在移动设备上使用
本博客主要围绕SQLite展开讲述,其实已经非常便捷和成熟的SQLite封装的工具,有兴趣的可以可以网上搜索一下几个框架去了解:

开源库 ---OrmLite开源库 ---greenDAO开源库 ---SugarORM开源库 ---ActiveAndroid开源库 ---LitePal开源库 ---realm

重述SQLite数据优点

在这里重复简述一下SQLite的特点:

1、SQLite作为一个轻型的关系型数据库;2、运算速度非常快,占用资源很少;3、SQLite不仅支持标准的SQL语法,还遵守了数据库的 ACID 事务,上手快;4、提供了零配置运行模式;5、无需服务进程,轻量、跨平台、多语言接口及安全性等;

SQLite数据库的使用

一、创建数据库方式

创建数据主要有四种方式:

1、create 在内存中创建数据库,当数据库关闭时即销毁;
2、openOrCreateDatabase 创建并打开数据库;
3、继承SQLiteOpenHelper类,且通过getWritableDatabase和getReadableDatabase方法创建;
4、openDatabase 创建并打开数据库,可以指定打开方式;

create简述

    /**     * Create a memory backed SQLite database.  Its contents will be destroyed     * when the database is closed.     *     * 

Sets the locale of the database to the the system's current locale. * Call {@link #setLocale} if you would like something else.

* * @param factory an optional factory class that is called to instantiate a * cursor when query is called * @return a SQLiteDatabase object, or null if the database can't be created */
public static SQLiteDatabase create(CursorFactory factory) { // This is a magic string with special meaning for SQLite. return openDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH, factory, CREATE_IF_NECESSARY); }

通过查看源码,我们可以发现,使用create方式创建数据库,最终是调用openDatabase方式来实现数据库的创建。

openOrCreateDatabase简述

       /**     * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).     */    public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {        return openOrCreateDatabase(file.getPath(), factory);    }    /**     * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).     */    public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {        return openDatabase(path, factory, CREATE_IF_NECESSARY, null);    }    /**     * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler).     */    public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,            DatabaseErrorHandler errorHandler) {        return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);    }    

通过查看源码,openOrCreateDatabase方式创建数据库,不管是带两个参数,还是三个,最终是通过调用openDatabase方式来实现数据库的创建。

getWritableDatabase和getReadableDatabase简述

     * Create and/or open a database that will be used for reading and writing.     * The first time this is called, the database will be opened and     * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be     * called.     *     * <p>Once opened successfully, the database is cached, so you can     * call this method every time you need to write to the database.     * (Make sure to call {@link #close} when you no longer need the database.)     * Errors such as bad permissions or a full disk may cause this method     * to fail, but future attempts may succeed if the problem is fixed.</p>     *     * <p class="caution">Database upgrade may take a long time, you     * should not call this method from the application main thread, including     * from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.     *     * @throws SQLiteException if the database cannot be opened for writing     * @return a read/write database object valid until {@link #close} is called     */    public SQLiteDatabase getWritableDatabase() {        synchronized (this) {            return getDatabaseLocked(true);        }    }private SQLiteDatabase getDatabaseLocked(boolean writable) {        ...        SQLiteDatabase db = mDatabase;        try {            mIsInitializing = true;            if (db != null) {                if (writable && db.isReadOnly()) {                    db.reopenReadWrite();                }            } else if (mName == null) {                db = SQLiteDatabase.create(null);            } else {                try {                    if (DEBUG_STRICT_READONLY && !writable) {                        final String path = mContext.getDatabasePath(mName).getPath();                        //位置1                        db = SQLiteDatabase.openDatabase(path, mFactory,                                SQLiteDatabase.OPEN_READONLY, mErrorHandler);                    } else {                    //位置2                        db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?                                Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,                                mFactory, mErrorHandler);                    }                } catch (SQLiteException ex) {                    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();                    //位置3                    db = SQLiteDatabase.openDatabase(path, mFactory,                            SQLiteDatabase.OPEN_READONLY, mErrorHandler);                }            }            ...    }

同样通过分析源码,我们可以看到getWritableDatabase和getReadableDatabase两个方法最终会调用getDatabaseLocked方法,而在getDatabaseLocked方法内,通过位置1、位置2和位置3我们可以分析得出结果,getWritableDatabase和getReadableDatabase方式创建数据,最终也是通过调用openDatabase方式来实现数据库的创建。

openDatabase简述
通过分析create方式、方式、openOrCreateDatabase、getWritableDatabase和getReadableDatabase方式创建数据的源码,得出在最终是通过openDatabase方式来创建数据库的,所以这里我们做种分析一下openDatabase方法;

   /**     * Open the database according to the flags {@link #OPEN_READWRITE}     * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.     *     * 

Sets the locale of the database to the the system's current locale. * Call {@link #setLocale} if you would like something else.

* *

Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be * used to handle corruption when sqlite reports database corruption.

* * @param path to database file to open and/or create * @param factory an optional factory class that is called to instantiate a * cursor when query is called, or null for default * @param flags to control database access mode * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption * when sqlite reports database corruption * @return the newly opened database * @throws SQLiteException if the database cannot be opened */
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags, DatabaseErrorHandler errorHandler) { SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler); db.open(); return db; }

openDatabase方法分别有四个参数:
第一个参数:path代表着数据库的路径(如果是在默认路径/data/data//databases/下,则这里只需要提供数据库名称);
第二个参数:factory代表着在创建Cursor对象时,使用的工厂类,如果为null的话,则使用默认的工厂(这里我们可以实现自己的工厂进行某些数据处理);
第三个参数:flags代表的是创建表时的一些权限设置,多个权限之间用|分隔:

权限 权限说明
OPEN_READONLY 代表的是以只读方式打开数据库(常量值为:1)
OPEN_READWRITE 代表以读写方式打开数据库(常量值为:0)
CREATE_IF_NECESSARY 当数据库不存在时创建数据库
NO_LOCALIZED_COLLATORS 打开数据库时,不根据本地化语言对数据库进行排序(常量值为:16)

第四个参数:errorHandler数据损坏时的回调参数(可null);

二、创建数据库

以上介绍的四种创建数据库的方式,最终目的就是为了得到SQLiteDatabase对象,因为只有在得到了SQLiteDatabase对象,才能对相应的数据库增、删、改、查,一下用代码形式简单表述一下用以上四种方式获取SQLiteDatabase对象。

create方式获取数据库对象

//在内存中创建数据库,当数据库关闭时即销毁;SQLiteDatabase database = null;  database = SQLiteDatabase.create(null);

openOrCreateDatabase方式获取数据库对象

   SQLiteDatabase database = null;method 1//file_path为文件存储路径File file = new File("file_path");database = SQLiteDatabase.openOrCreateDatabase(file, null);method 2//data_name为数据名称,且创建的数据库是在默认路径/data/data//databases/下String dataName = "data_name.db";database = SQLiteDatabase.openOrCreateDatabase(dataName, null);//第3种方式和第2中方式没有本质上的区别,区别在于是否对数据损坏进行监测method 3//data_name为数据名称,且创建的数据库是在默认路径/data/data//databases/下String dataName = "data_name.db";database = SQLiteDatabase.openOrCreateDatabase(dataName, null, null);

openDatabase方式获取数据库对象

   SQLiteDatabase database = null;method 1//data_name为数据名称,且创建的数据库是在默认路径/data/data//databases/下String dataName = "data_name.db";database = SQLiteDatabase.openDatabase(dataName, null, CREATE_IF_NECESSARY);method 2//data_name为数据名称,且创建的数据库是在默认路径/data/data//databases/下String dataName = "data_name.db";database = SQLiteDatabase.openDatabase(dataName, null, CREATE_IF_NECESSARY, null);

getWritableDatabase和getReadableDatabase方式获取数据库对象

在使用前简单介绍一下SQLiteOpenHelper抽象类,SQLiteOpenHelper是SQLiteDatabase的帮助类, 用于管理数据库的创建和升级。
需要一个继承SQLiteOpenHelper抽象类的自定义类,我们通过继承该类,然后重写数据库创建以及更新的方法, 我们还可以通过该类的对象获得数据库实例,或者关闭数据库;

a、首先需要实现一个自定义类继承于SQLiteOpenHelper

public class DBOpenHelper extends SQLiteOpenHelper {    // 相当于 SQLiteDatabase openDatabase(String, CursorFactory)    public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {        super(context, name, factory, version);    }    // 相当于 SQLiteDatabase openDatabase(String, CursorFactory, DatabaseErrorHandler)    @TargetApi(Build.VERSION_CODES.HONEYCOMB)    public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version,    DatabaseErrorHandler errorHandler) {        super(context, name, factory, version, errorHandler);    }    // 相当于 SQLiteDatabase openDatabase(String , OpenParams);    @TargetApi(Build.VERSION_CODES.P)    public DBOpenHelper(Context context, String name, int version, SQLiteDatabase.OpenParams openParams) {        super(context, name, version, openParams);    }    // 创建数据文件时调用,此时适合创建新表    @Override    public void onCreate(SQLiteDatabase db) {    }    // 更新数据库版本时调用,适合更新表结构或创建新表    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

b、其次通过实现DBOpenHelper类,在通过实现该类得到的对象,调用getWritableDatabase或getReadableDatabase方法实现创建数据库,如下:

SQLiteDatabase database = null;//data_name为数据名称,且创建的数据库是在默认路径/data/data//databases/下String dataName = "data_name.db";// 生成 helper 对象,可以打开数据库文件。文件名可以是相对路径或绝对路径DBOpenHelper dbHelper = new DBOpenHelper(this, dataName, null, 1);// 用读写的方式打开数据库文件database = dbHelper.getWritableDatabase();

备注:如果不采用第三方框架的情况下,只是在内部存储设备中创建数据库,最好在使用getWritableDatabase和getReadableDatabase方式获取数据库对象,如果是有需要使用外部数据,那么可以使用openOrCreateDatabase方式。

三、数据库的增删改查操作

在第二部分中,我们通过四种方式中的任何一种方式,获取SQLiteDatabase对象,通过该对象我们可以实现接下来的增删改查功能。

新增数据

/** * 向数据库插入一行数据 * * @param table 指定表名,插入一行数据 * @param nullColumnHack 可选参数,建议是 null *            如果设置 null,将不允许向表中插入空数据,即 values = null 时无法正确执行插入操作。 *            如果不设置 null,那么需要设置表中可以为空的属性列的名称。 *            当 values = null 时,可以向表中插入空数据。 *            而实际上是插入一行数据,只有属性列名 nullColumnHack 的值是 null。  * @param values map 集合,包含需要插入的一行数据。至少需要包含一个属性的 key 和 value。 *            key 是属性列名称,value 是属性值。 * @return 返回新插入的行序号, 发生错误时,返回 -1 */public long insert(String table, String nullColumnHack, ContentValues values) {    try {        return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);    } catch (SQLException e) {        Log.e(TAG, "Error inserting " + values, e);        return -1;    }}

exp:

/** * SQL插入语句: * INSERT INTO tab(param1,param2,param3) VALUES ("param1","param2","param3"); */method 1:String sql = "INSERT INTO tab VALUES(?,?,?)";database.execSQL(sql,new String[]{"param1","param2","param3"});method 2:ContentValues contentValues = new ContentValues();contentValues.put("param1", "param1");contentValues.put("param2", "param2");contentValues.put("param3", "param3");/** * @第一参数 table 指定表名,插入一行数据 * @第二参数 nullColumnHack 可选参数,建议是 null *            如果设置 null,将不允许向表中插入空数据,即 values = null 时无法正确执行插入操作。 *            如果不设置 null,那么需要设置表中可以为空的属性列的名称。 *            当 values = null 时,可以向表中插入空数据。 *            而实际上是插入一行数据,只有属性列名 nullColumnHack 的值是 null。  * @第三参数 values map 集合,包含需要插入的一行数据。至少需要包含一个属性的 key 和 value。 *            key 是属性列名称,value 是属性值。 * @return 返回新插入的行序号, 发生错误时,返回 -1 */database.insert("tab", null, contentValues);

删除数据

/** * 删除数据库中一行的方法 * * @param table 需要删除的表名 * @param whereClause 传入 null 时表示删除表中全部数据。 *            或者指定删除条件,只会删除满足条件的行。 * @param whereArgs 指定删除条件的值,按照顺序替换在删除条件中的 ? 。 * @return 删除满足条件的行时,返回删除的行数。找不到满足条件删除的时候,返回 0 。 */public int delete(String table, String whereClause, String[] whereArgs) {    acquireReference();    try {        SQLiteStatement statement =  new SQLiteStatement(this, "DELETE FROM " + table +                (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);        try {            return statement.executeUpdateDelete();        } finally {            statement.close();        }    } finally {        releaseReference();    }}

exp:

/** *SQL删除语句: * DELETE FROM tab WHERE param1 = 'param1'; */method 1:String sql = "DELETE FROM tab WHERE param1 = ?";database.execSQL(sql,new String[]{"param1"});method 2:/** * @第一参数 table 需要删除的表名 * @第二参数 whereClause 传入 null 时表示删除表中全部数据。 *            或者指定删除条件,只会删除满足条件的行。 * @第三参数 whereArgs 指定删除条件的值,按照顺序替换在删除条件中的 ? 。 * @return 删除满足条件的行时,返回删除的行数。找不到满足条件删除的时候,返回 0 。 */database.delete("tab", "param1=?", new String[]{"param1"});

修改数据

/** * 更新数据库表中的一行数据 * * @param table 需要更新的表名 * @param values 包含属性名和新属性值的 map 集合。 * @param whereClause 可选的 WHERE 条件决定需要更新的行。 *            如果是空,则更新所有的行。 * @param whereArgs 替换在 where 条件中包含的 ? 。 * @return 返回更新的行数 */public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {    return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);}

exp:

/** * SQL更新语句: * UPDATE tab SET param1 = "newname" WHERE param1 = 'param1' ; */method 1:String sql = "UPDATE tab SET param1 = ? WHERE param1 = ?";database.execSQL(sql,new String[]{"newname", "param1"});method 2: ContentValues contentValues = new ContentValues();contentValues.put("param1", "newname");/** * @第一参数 table 需要更新的表名 * @第二参数 values 包含属性名和新属性值的 map 集合。 * @第三参数 whereClause 可选的 WHERE 条件决定需要更新的行。 *            如果是空,则更新所有的行。 * @第四参数 whereArgs 替换在 where 条件中包含的 ? 。 * @return 返回更新的行数 */database.update("tab", contentValues, "param1=?", new String[]{"param1"});

查询数据

/** * 查询数据库插数据 * * @param sql 所有的 query 方法,最后都会合并出 sql 执行 rawquery 方法 * @param selectionArgs 替换在 selection 中使用的 ? 或 sql 中使用的 ?。 * @return 返回Cursor(查询到的数据) */public Cursor rawQuery(String sql, String[] selectionArgs) {    return rawQueryWithFactory(null, sql, selectionArgs, null, null);}

exp:

/** * SQL查询语句: * SELECT * FROM tab ; */String sql = "SELECT * FROM tab";Cursor cursor = database.rawQuery(sql, null);

四、事务处理

事务(Transaction)是一个对数据库执行工作单元。事务(Transaction)是以逻辑顺序完成的工作单位或序列,可以是由用户手动操作完成。SQLite 事务主要提供了三个 API。在结束事务前,如想将事务提交到数据库,需要设置事务完成标记。否则,在事务开启时候做的数据库操作将不会保留。
exp:

database.beginTransaction();....../* 此处执行数据库操作 */......database.setTransactionSuccessful();database.endTransaction();

简述查询返回的Cursor对象

cursor(游标)是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果

cursor常用方法介绍:1、moveToFirst():将指针移动到结果集的第一行;2、getColumnIndex():获取某一列在表中对应位置的索引;3、close():关闭指针。4、move(int offset):以当前位置为参考,移动到指定行5、moveToLast():移动到最后一行6、moveToPosition(int position):移动到指定行7、moveToPrevious():移动到前一行8、moveToNext():移动到下一行9、isFirst():是否指向第一条10、isLast():是否指向最后一条11、isBeforeFirst():/是否指向第一条之前12、isAfterLast():是否指向最后一条之后13、isNull(int columnIndex):指定列是否为空(列基数为0)14、isClosed():游标是否已关闭15、getCount():总数据项数16、getPosition():返回当前游标所指向的行数17、getString(int columnIndex):返回当前行指定列的值

exp:

 Cursor cursor = database.rawQuery("select * from tab", null);while (cursor.moveToNext()) {    String param1= cursor.getString(cursor.getColumnIndex("param1"));    String param2= cursor.getString(cursor.getColumnIndex("param2"));    String param3= cursor.getString(cursor.getColumnIndex("param3"));}cursor.close();

备注

Android数据库存储到此基本也介绍完了,其实这些都非常基础的数据库处理方式,如果你对Android原生的数据库创建方式感觉繁琐,其实你考虑使用第三方开源库。开源库在某种程度上简化了数据创建以及增删改查等功能。
到此Android的三大数据持久化存储(SharePreferences存储、文件存储、数据库存储)之数据库存储就介绍到这了。

更多相关文章

  1. Android (SQLite 数据库与ContentProvider)
  2. 无废话Android之android下junit测试框架配置、保存文件到手机内
  3. 王家林,云计算,大数据,Hadoop,Android,iOS,HTML5,Linux----王家林一站式
  4. Android XML解析学习——Dom方式
  5. Android 使用OpenCV的三种方式(Android Studio)
  6. Google公布Android数据,年增长250%,每天激活85万台Android设备
  7. 安卓软硬结合,热点技术实践总结:《Android音频口数据通信开发》 |
  8. android原生SQLite数据库的使用

随机推荐

  1. android电话拦截及短信过滤
  2. Android定位获取当前经纬度
  3. Android开发环境配置
  4. 转化为当前的日期和时间
  5. Android中的Bundle学习
  6. Android(安卓)GPS架构分析(二)
  7. Android(安卓)dialog 全屏
  8. Android(安卓)动画之ScaleAnimation应用
  9. Android(安卓)七种对话框使用
  10. android(6) 扇形菜单实现