Android编程学习笔记 之 SQLite数据存储

来源:互联网 发布:nginx cgi 编辑:程序博客网 时间:2024/05/16 16:11

SQLite是一个轻量级的嵌入式的数据库,我们在Android开发中不需要安装任何插件即可使用,

如果是root过的手机,可以在data/data/包名/databases里面找到db数据库文件,推荐用SQLiteSpy或sqlite3进行查看

支持高达2TB大小的数据库,以单个文件形式存在,以B-树的数据结构形式存储。

在安全性方面,允许多个进程同时读,只允许一个进程进行写。(以上概念可以无视


SQLite支持的数据类型和我们编程时用的数据类型有所不同。

支持null(空值),integer(整型),real(浮点型),text(字符串),blob(二进制型)

虽然还支持动态数据类型,自动检测值的类型,进行强制转换,但是还是推荐严格的使用上述数据类型。


我们先来认识一下这两个类SQLiteDatabase和SQLiteOpenHelper,有个大致印象。

SQLiteDatabase:管理SQLite,进行增、删、查、改操作。

SQLiteOpenHelper:是SQLiteDatabase的帮助类,用于管理数据库的创建和版本更新。


我们在Android开发中使用SQLite进行数据存储大致的步骤如下:

创建或打开SQLite数据库,创建或打开一个表Table

进行增、删、查、改操作

关闭数据库手动释放内存


创建或打开SQLite数据库,创建或打开一个表Table

每个程序都有自己的数据库,互不干扰。如果要访问其他应用程序的数据库的话,博主还没研究到,这里待补充

一般的Android开发中建库建表都是由SQLiteOpenHelper进行封装的实现的,好处就是,我们在Activity中进行建表建库操作时不用关心具体的实现

我们需要写一个类继承它,重写其中的onCreat()onUpgrade()方法,下面简单介绍下SQLiteOpenHelper常用的方法

  1. void onCreate(SQLiteDatabase db):创建数据库时调用,建库建表的操作
  2. void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):版本更新时调用,自动执行
  3. SQLiteDatabase getReadableDatabase():创建或打开一个只读数据库,只能查询,不能写入,不能更新,并返回一个SQLiteDatabase对象
  4. SQLiteDatabase getWritableDatabase():创建或打开一个读写数据库,并返回一个SQLiteDatabase对象
public class MySQLiteOpenHelper extends SQLiteOpenHelper {    public MySQLiteOpenHelper(Context context, String name) {        super(context, name, null, 1);//自定义构造函数,建立名为name的数据库    }    public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {        super(context, name, factory, version);//context表示上下文,name表示数据库的名字,version表示数据库的版本号        //factory可选的数据库游标工厂类,当查询(query)被提交时,该对象会被调用来实例化一个游标。默认为null。    }    @Override    public void onCreate(SQLiteDatabase sqLiteDatabase) {//创建数据库时调用,建库建表的操作        sqLiteDatabase.execSQL("create table if not exists Student(" + //如果不存在Student表,则建表                "_id integer primary key autoincrement," +             //以自增的integer类型的_id为主键                "name text not null" +                                 //添加不允许为null的名为name的text类型的一列                "age integer not null)");                              //添加不允许为null的名为age的integer类型的一列    }    @Override    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {        //数据库版本更新时调用,自动执行,不用手动调用,比如增加了一列数据    }}

这里还有些SQL语句的小知识,有兴趣可以点击超链接查看

  1. 主键前要加下划线
  2. _id必须要int最好Integer
  3. primary key声明为主键(允许有多个主键)
  4. autoincrement自增
  5. not null不允许为空
原生的SQL建表语句如下:
create table if not exists 表名(主键名 数据类型 primary key autoincrement,数据名 数据类型 not null)create table if not exists table(_id integer primary key autoincrement, name text not null, age integer not null)

写好这个SQLiteOpenHelper类后,我们在Activity中实例化这个SQLiteOpenHelper,并传入上下文context和数据库的名字mydb。

就可以用getReadableDatabase()或者getWritableDatabase()获得一个SQLiteDatabase对象,自此,建库建表完成。

    MySQLiteOpenHelper mySQLiteOpenHelper = new MySQLiteOpenHelper(this, "mydb");    SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
实际上,这样的建库建表还是不够底层的,在super里面建库建表调用了openOrCreateDatabase()方法,有兴趣的可以查阅API
SQLiteDatabase db = openOrCreateDatabase(String name, int mode, CursorFactory factory));//打开本应用程序的数据库//name建议加上db的后缀,在其他设备(电脑)打开,表示数据库的名字//mode在之前有SharedPrefen讲过,有私有,只读,//factory可选的数据库游标工厂类,当查询(query)被提交时,该对象会被调用来实例化一个游标。默认为null。

附:博主以前写记事本App的时候,在Activity中使用了如下语句进行创建数据库(不建议使用

是通过绝对路径来新建一个数据库,

第一个参数是绝对路径,第二个参数是CursorFactory是一个用于返回的Cursor工厂,如果为null,则使用默认的工厂。

SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(this.getFilesDir().toString() + "/note.db3", null);//可以打开其他程序的数据库?


进行增、删、查、改操作

进行SQL数据库增、删、查、改操作分为两种方式:

一种是使用execSQL输入原生的SQL语句,效率低难查错,不能错一个字母一个空格,要求严格输入,开发时不推荐使用,写Demo时可以熟悉练手

一种是用Android自带的简化版的封装好的方法进行增删查改。

我们这里就不详细介绍原生的SQL语句,有兴趣可以点击上方的超链接。

SQLiteDatabase的常用方法void execSQL(String sql)执行原生的SQL语句long insert(String table, String nullColumnHack, ContentValues values)在table表中,插入values的一行数据,如果values有null,则用nullColumnHack填充null值所在的列名,返回插入的是第几行int delete(String table, String whereClause, String[] whereArgs)在table表中,删除满足whereArgs数据的whereClause条件,返回删除的是第几行int update(String table, ContentValues values, String whereClause, String[] whereArgs)在table表中,更新满足whereArgs数据的whereClause条件,用values进行修改更新的一行数据,返回更新的是第几行Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
Cursor rawQuery(String sql, String[] selectionArgs)使用原生的sql语句查找,将String类型的sql中的?替换为selectionArgs中的数据













在进行增删查改操作之前,我们先要认识下两个类ContentValuesCursor,这两个我们可以理解为就是存储了一行的数据,前者存放,后者读取

ContentValues用来存储一组可以被ContentResolver处理的值,类似Map,采用键值对的方式存储key-value

Cursor翻译为游标,是Android查询数据后得到的一个管理数据集合的类,类似于List集合,推荐手动释放内存,避免内存溢出。


增:

其实就是插入。

原生的SQL语句是类似键值对的方式存入的。

insert into 表名(数据名...) values(数据的值...)insert into table(name, age) values('小明', 18)
在Android的方法中,我们需要用到ContentValues来存储一行的数据,和Map<String key, Object value>很像
contentValues.put("key", value);//键值对存储db.insert(String table, String nullColumnHack, ContentValues contentValues)//返回插入到第几行,返回新添记录的行号,与主键id无关db.insert(表名, 当contentValues为null时该列的名称, 一行的数据)

一般情况下,只要contentValues不为null,nullColumnHack都不起作用,所以nullColumnHack设置为null即可。

并且nullColumnHack的列名不能是主键列的列名,也不能是非空列的列名

当这一行添加完毕,记得将contentValues清空,或者重新new一个对象

contentValues.clear();//添加新数据的时候要记得清空,这是一行的数据


改:

也就是更新,update,同样需要contentValues来进行存储数据,这里就给个用法。

同样,每次更新完都要将contentValues清空,或者重新new一个对象

int update(String table, ContentValues values, String whereClause, String[] whereArgs)int update(表名, 一行的数据, 限制条件, 限制条件的值)int update("table", values, "_id>?", new String[]{"3"});//更新所有_id>3的数据为contentValues


删:

顾名思义,就是删除,不需要借助ContentValues和Cursor

int delete(String table, String whereClause, String[] whereArgs  )int delete(表名, 限制条件, 限制条件的值)int delete("table", "name like ?", new String[]{"%明%"});//%是通配符,删除所以名字中带有"明"的人


查:

查找,这里需要用到Cursor游标,Cursor类似于List<Map<String key, Object value>>,可以看成是符合搜索条件的行组成的一个子表的指针

Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs,                                             String groupBy, String having, String orderBy, String limit)Cursor query(是否去重, 表名, 返回的列名, 查询条件, 查询条件的值, 控制分组, 控制过滤, 控制排序, 控制查找的数据数)Cursor query(true, "table", null为返回所有列, "_id>?", new String[]{"0"}, null, null, "name", null);//查询所有_id>0的数据,并按name升序排序Cursor rawQuery(String sql, String[] selectionArgs)

query和rawQuery的区别在于:

query是Android自己封装的API,不容易出错

rawQuery是直接使用SQL语句进行查询的,也就是第一个参数字符串,在字符串内的“?”会被后面的String[]数组逐一对换掉。


他们都返回一个Cursor,可以看成是符合搜索条件的行组成的一个子表的指针,默认指向第一行,Cursor有一些方法

int getCount();//返回总记录条数boolean isFirst();//当前游标是否指向第一条记录,成功则返回true,失败返回falseboolean isLast();//当前游标是否指向最后一条记录boolean moveToFirst();//当前游标移动到第一条记录,默认在第一行boolean moveToLast();//当前游标移动到最后一条记录boolean move(int position);//当前游标移动到第position条记录boolean moveToNext();//当前游标移动到下一条记录boolean moveToPrevious();//当前游标移动到上一条记录int getColumnIndexOrThrow(String columnName);//根据columnName列名获取第几列的数据,返回第几列int getInt(int columnIndex);//获得指定列索引的值,转成int型String getString(int columnIndex);//获得指定列索引的值,转成String型,还有其他就不一一列举

在查找完毕后,我们需要手动关闭Cursor

//Cursor默认在第一行,if(cursor!=null){    while(cursor.moveToNext()){//移向下一行       Log.i("info", "_id:"+cursor.getInt(cursor.getColumnIndex("_id")));//获取名为_id的列的,在这一行的int值        Log.i("info", "name:"+cursor.getString(cursor.getColumnIndex("name")));        Log.i("info", "age:"+cursor.getInt(cursor.getColumnIndex("age")));    }    cursor.close();//关闭Cursor}db.close();


关闭数据库手动释放内存

最后关闭数据库

db.close();

最后,虽然SQL原生语句写起来可能会很容易出错,但是还是要去学习,SQL语句对一个程序员是很重要的基本功。


0 0
原创粉丝点击