Android SQLiteDatabase

来源:互联网 发布:交通组织优化方案 编辑:程序博客网 时间:2024/05/21 06:34

Android - SQLite数据库

程序中使用数据库,通常是:

  • 设计表结构
    • 需要哪些表
    • 表之间的关系
    • 有哪些字段
  • 创建数据库
    • 数据库名称
    • 存储路径
    • 文件大小
  • 创建表
    • 字段相关内容
  • 业务相关 (根据不同的需求,可选)
    • 视图
    • 存储过程
    • 函数

那下面来看下我们Android中数据库的操作,更多内容请看:SQLite文档

设计表结构 (Contract)

程序中需要哪些表,有哪些列(字段,属性),表之间的关系…

以前写Java程序时是通过写JavaBean类,在bean包下创建很多个实体类,在Android中,Google建议我们使用 Contract(契约类)

契约类 :是用于定义 URI、表格和列名称的常数的容器

项目经验很少,并不是很懂写契约类,和那些实体类相比有什么大大的优势,只是在结合ContentProvider时,契约类更能派上用场,好吧,留待以后慢慢体会,接着写…

我们简单的写一个学生信息(Student)的增删改查(CRUD)好了

看下契约类长什么样子

~~~
// 定义学生管理系统的契约类
public final class StudentContract {
// 私有化构造器,避免创建对象,因为我们不用该类对象
private StudentContract() {}

// 定义Student表内容的内部类public static class StudentEntry implements BaseColumns {    public static final String TABLE_NAME = "student";    public static final String COLUMN_STU_NAME = "stuName";    public static final String COLUMN_STU_AGE = "stuAge";}

}
~~~

这里我们只使用了一张表,如果有多张表,那么就在契约类中添加定义表内容的内部类,就像StudentEntry类一样。

看到我们的 StudentEntry 类实现了 BaseColumns 接口,BaseColumns接口中只有两个字段,一个是 _ID ,另一个是 _COUNT,也就是说StudentEntry设计的表有5列。其中_ID那一列作为主键。

以上就是定义表结构,其实就是定义几张不同的表,它有哪些列。最后看下我们上述实现的表的图示。

表结构图

创建数据库 (SQLiteOpenHelper)

表的结构定义完成,那我们是不是按照契约创建数据库,创建表了?答案是肯定的。

创建数据库,必然少不了操作数据库的类,Android中给我们提供了SQLiteDatabase 类来进行数据库的相关操作,我们要创建数据库,来看下API,有没有创建数据库的方法。

  • 嘿,找到了 create() ,看下方法的文档说明,咦,当数据库关闭时,数据库内容就被销毁了???(关于create方法,里面有一个In-Memory Database的概念,感兴趣的同学可以去了解下),HAi,这方法不行啊。

  • 接着看API….,哈哈,不看了

  • 好吧,不卖关子了,其实所有的创建数据库的方法(create()、openDatabase(重载)、openOrCreateDatabase(重载)),最终都会执行openDatabase(String path,CursorFactory factory, int flags,DatabaseErrorHandler errorHandler)

看下它是怎么创建

public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,DatabaseErrorHandler errorHandler) {        SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);        db.open();        return db;    }

嘿呀,流了一大把汗终于把数据库new出来了,哎,下面db.open(),打开数据库?是的,我们的数据库并不是new出来就能增删改查的,它要创建并且打开后才能使用它进行CRUD操作的。

  • 数据库创建

    • path : 数据库创建了,保存的路径,这个路径包含数据库的名称吧,假如我们没有给数据库起名字?是不是很嗨?后面我们使用SQLiteOpenHelper时,会有这个参数,假如传递null,即不给它起名字,那么它便会创建一个”In-Memory Database” ,这里是 In-Memory Databases文档

    • flags : 这里会有打开的方式(只读 or 读写),假如我们以只读的方法打开了,那么我们只能查询,怎么增删改呢?那就以全以读写的方式打开啊,那我们的数据库部分内容只有有权限的人进行增删改呢,那就让它以只读方法打开啊。嘿,就一个打开就这么麻烦的吗?

  • 数据库更新

    • 业务需求的变更,数据库的表结构可能也要有相应的更改,那数据库的更新该怎么做呢?向上升级,向下降级

    • 升级或者降级,需要备份当前数据库后删除,然后导入新的数据库中,删除和导入的过程中出现了问题怎么办?还要使用数据库事务,开启事务,删除,导入,关闭事务。

据上所述,数据库的创建,和版本更新是一个比较复杂的事情,因此Google给我们提供了一个便于数据库创建和版本更新的辅助工具类 SQLiteOpenHelper ,查看文档,我们会发现它不仅在创建和版本更新上有优势,在和ContentProvider结合使用时还有它别的优势。

  • 其实在初学时,我们并不会有那么复杂的业务,就一个简单增删改查的方法调用,直接一个openOrCreateDatabase()就可以了啊,因此SQLiteOpenHelper的使用不是必须的,但是,它又是必须的,因为我们不会一直是初学者。养成良好的编程风格。

  • SQLiteOpenHelper是一个辅助类,用于方便我们数据库的创建和更新,还有一个,数据库的创建通常会保存在SDCard中,因此我们自己也可以写一个SQLiteOpenHelper,其中封装一些操作SDCard路径的内容等等类似的SQLiteHelper。

上面说了一些关于我对为何使用SQLiteOpenHelper的理解。下面来看下SQLiteOpenHelper的使用吧。

public class DbHelper extends SQLiteOpenHelper {    private static DbHelper sInstance;    //单例设计模式,确保程序中只有一个Database实例对象,避免Leak错误    public static synchronized DbHelper getInstance(Context context) {        if (sInstance == null) {            sInstance = new DbHelper(context.getApplicationContext());        }        return sInstance;    }    private static final String DATABASE_NAME = "student.db";    private static final int DATABASE_VERSION = 1;    // 私有化DbHelper类构造器,只通过getInstance方法获取DbHelper实例    private DbHelper(Context context) {        super(context, DATABASE_NAME, null, DATABASE_VERSION);    }    // 创建数据库    @Override    public void onCreate(SQLiteDatabase db) {    }    // 更新数据库    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

嗯,大概的样子有了,结合我们的实例,学生信息管理开看下,具体的Helper中该添加哪些内容吧。

数据库操作

  • 添加创建和删除的表的SQL语句
public class DbHelper extends SQLiteOpenHelper {    ......    // 创建student表的sql语句    private static final String SQL_CREATE_TABLE_STUDENT =             "CREATE TABLE " + StudentContract.StudentEntry.TABLE_NAME + " (" +            StudentContract.StudentEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +            StudentContract.StudentEntry.COLUMN_STU_NAME + " TEXT NOT NULL, " +            StudentContract.StudentEntry.COLUMN_STU_AGE + " INTEGER" +            ");";    // 删除student表的sql语句    private static final String SQL_DELETE_TABLE_STUDENT =             "DROP TABLE IF EXISTS " + StudentContract.StudentEntry.TABLE_NAME;      ......   }
  • 再看onCreate()和onUpdate()方法中怎么写
public class DbHelper extends SQLiteOpenHelper {    ......    // 创建数据库    @Override    public void onCreate(SQLiteDatabase db) {        // 执行创建语句        db.execSQL(SQL_CREATE_TABLE_STUDENT);    }    // 更新数据库    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        //执行删除语句        db.execSQL(SQL_DELETE_TABLE_STUDENT);        //重新创建表        onCreate(db);    }}

这里只是给出了简单的Helper怎么写,那么具体的我们可以参考Google的代码,这里有个Google I/O 2016官方APP的源码,我们可以去看看大厂是如何写Helper的:ScheduleDatabase类 ,参考并学习它是如何创建和实现版本更新的。

哈,创建数据库写了太多内容了,下面简单写下SQLiteDatabase的C(create)、R(retrieve)、U(update)、D(delete)数据操作的方法好了(因为,网上一大把关于SQLiteDatabase的CRUD操作的文章)。

为了功能分离,我单独创建了一个StudentDb类来是先数据的增删改查

public class StudentDb {    // Database由DbHelper来创建,因此需要添加依赖    private DbHelper mDbHelper;    public StudentDb(DbHelper dbHelper) {        mDbHelper = dbHelper;    }    //添加    public long insert(){        return 0;    }    //删除    public void delete(){    }    //修改    public int update(){        return 0;    }    //查找    public Cursor select(String name){        return null;    }}
  • C_添加数据 (create)
    public long insert(String name, int age) {        // 获取数据库对象        SQLiteDatabase db = mDbHelper.getWritableDatabase();        // 用ContentValues装载要保存的数据        ContentValues values = new ContentValues();        values.put(StudentContract.StudentEntry.COLUMN_STU_NAME, name);        values.put(StudentContract.StudentEntry.COLUMN_STU_AGE, age);        // 插入数据        return db.insert(StudentContract.StudentEntry.TABLE_NAME, null, values);    }

这里是参数用String name ,int age,当字段很多时呢?我们可以在别处封装数据,传递ContentValues参数就行了。

  • R_查询数据(retrieve)
    public Cursor select(String name) {        // 获取数据库对象        SQLiteDatabase db = mDbHelper.getReadableDatabase();        // 要查询的列        String[] projection = {                StudentContract.StudentEntry._ID,                StudentContract.StudentEntry.COLUMN_STU_NAME,                StudentContract.StudentEntry.COLUMN_STU_AGE};        // 查询条件        String selection = StudentContract.StudentEntry.COLUMN_STU_NAME + " = ?";        String[] selectionArgs = {name};        // 排序条件        String sortOrder =                StudentContract.StudentEntry.COLUMN_STU_AGE + " DESC";        return db.query(                StudentContract.StudentEntry.TABLE_NAME,  // 要查询的表名称                projection,                               // 要查询的列                selection,                                // 查询条件列                selectionArgs,                            // 查询条件值                null,                                     // 不使用group by                null,                                     // 不使用having                sortOrder                                 // 分组条件        );    }

要查询的列,如果全都查询的话,直接输入null,没有查询条件的话也是输入null。

  • U_更新数据(udpate)
    public int update(String oldName, String newName) {        // 获取数据库对象        SQLiteDatabase db = mDbHelper.getReadableDatabase();        // 新数据        ContentValues values = new ContentValues();        values.put(StudentContract.StudentEntry.COLUMN_STU_NAME, newName);        // 更新记录的过滤条件        String selection = StudentContract.StudentEntry.COLUMN_STU_NAME + " LIKE ?";        String[] selectionArgs = {oldName};        //更新        return db.update(                StudentContract.StudentEntry.TABLE_NAME,                values,                selection,                selectionArgs);    }
  • D_删除数据(delete)
    public int delete(String name) {        // 获取数据库对象        SQLiteDatabase db = mDbHelper.getWritableDatabase();        // 删除记录的过滤条件        String selection = StudentContract.StudentEntry.COLUMN_STU_NAME + " LIKE ?";        String[] selectionArgs = {name};        // 删除        return db.delete(                StudentContract.StudentEntry.TABLE_NAME,                selection,                selectionArgs);    }

由上可以看出

  • 当进行查找,数据库中数据不发生变化时,使用helper的getReadableDatabase()方法

  • 当进行增删改,数据发生变化时,我们使用helper的getWritableDatabase()方法

  • 使用已经封装好了的query()方法似乎参数太多,不太好用,再加上爱装逼的我们,使用SQL脚本多好呐。哈哈,好吧,开个玩笑,Google为我们不仅仅提供这种便捷的方法,还提供了一种通用的execSQL()方法,另外还有单门执行select语句的rawQuery()方法。呐,具体用哪个看个人的喜好还有哪个更方便操作了。

至此,关于Android SQLite数据库的内容就结束了,感谢您的阅读。

如果你对我的文章感兴趣,欢迎关注我的微信公众号: oogh ,期待你的到来

0 0
原创粉丝点击