上一篇文章总结了文件存储和SharedPreference两种存储方式,我们知道这两种存储方式都只适合存储数据结构简单的数据,当我们需要存储类似表格数据时,Android 内置的SQLiteDatabase就派上了用场:
SQlite的基础使用
SQLite的最佳实践
SQlite的基础使用
创建数据库
升级数据库
添加数据
更新数据
删除数据
查询数据
创建数据库
在创建数据之前,我们需要学习一个类,就是SQLiteOpenHelper帮助类,借助这个类就可以非常简单的对数据库进行创建和升级。SQLiteOpenHelper是一个抽象类,我们需要自己写一个继承自SQLiteOpenHelper的类,会重写onCreate()和onUpgrade()两个方法。在这两个方法中执行创建和更新数据库的操作。
SQLiteOpenHelper中还有两个非常重要的实例方法,getReadableDatabase()和getWritableDatabase(),这两个方法都可以创建或打开一个现有的数据库(如果数据库已经存在则直接打开,否则创建一个新的数据库),并返回一个对数据库进行操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满)getReadableDatabase()方法返回的对象将只以只读的方式去打开数据库,而getWritableDatabase则将出现异常。
SQLiteOpenHelper中的两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。这个方法接收四个参数,第一个参数是Context,这个就是上下文对象,第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。第三个参数允许我们在查询数据的时候返回以个自定义的Cursor,一般都是传入null.第四个参数是表示当前数据库的版本号,可用于对数据库进行升级操作。
通过SQLiteDatabase的实例之后,再调用它的getReadableDatabase()或getWritableDatabase()方法就可以创建数据库了。
数据会存放在/data/data/包名/databases/
在示例中我们希望创建一个名为BookStore.db的数据库,然后在这个数据库中新建一张Book表,建表语句如下:
private static final String CREATE = "create table Book(id integer
primary key autoincrement,author text," +
" price real,pages integer," +
"name text,category_id integer)";
author text中的text就是文本格式,real 表示浮点数, integer表示整数型,在上述建表语句中我们使用了primary key 将id设为主键,并用auto increment关键字表示id 列是自增长的。
在SQLiteOpenHelper中,代码如下,此时数据库并没有创建,
//创建数据库,只执行一次,
private static final String CREATE = "create table Book(id integer
primary key autoincrement,author text," +
" price real,pages integer," +
"name text,category_id integer)";
private Context context1;
public MyDatabaseHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
context1 = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE);
db.execSQL(CREATE_CATEGORY);
Log.e("TAG", "onCreate");
}
还需要调用helper.getWritableDatabase();,此时数据库才创建完成。
helper = new MyDatabaseHelper(this, "Book.db", null,1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//获取数据库
helper.getWritableDatabase();
}
});
打开DDMS,在File Explore下找到应用的包名,然后找到我们刚才创建的数据库,导出后,使用查看数据库的软件或者工具查看,就可以我们创建的数据库
这样我们的数据库和一张名为Book的表就创建完成了。
升级数据库
执行完上面,会发现,onUpgrade()中没有写任何代码,假如我们现在有这样的一个需求,在数据库Book.db中添加一个新的表,Category,那么代码如下:
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "MyDatabaseHelper";
private static final String CREATE = "create table Book(id integer primary key autoincrement,author text," +
" price real,pages integer," +
"name text,category_id integer)";
private static final String CREATE_CATEGORY = "create table Category(id integer primary key autoincrement ," +
"category_name text," +
"category_code integer)";
private Context context1;
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
context1 = context;
}
//创建数据库,只执行一次,
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE);
db.execSQL(CREATE_CATEGORY);
Log.e("TAG", "onCreate");
}
//对数据库中的表的列目进行增删改查,或者添加表
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e(TAG, "onUpgrade");
switch (oldVersion) {
case 2:
db.execSQL(CREATE_CATEGORY);
default:
}
}
}
如上代码中,我们为什么在onCreate和onUpgrade两个方法中都执行了创建表的雨季呢,想象一下,你的用户并不是从你发布开始就使用你的程序,那么这时候,就会有老用户和新用户,我们要全部的考虑到,所以在两个方法中都有创建Category表的语句,就是为了,满足不同的用户。
当新用户安装时,就只会执行onCreate()方法
当老用户版本更新,就只会执行onUpgragde()方法
添加数据
前面说了数据库的创建和升级,但是数据库的作用主要是存储数据,现在我们插入两条数据库。
/**
* 插入数据
*/
private void insert() {
SQLiteDatabase database = helper.getWritableDatabase();
//插入一条数据
ContentValues values = new ContentValues();
values.put("author", "xiaokai");
values.put("price", 18);
values.put("pages", 289);
values.put("name", "平凡的世界");
database.insert("Book", null, values);
//插入第二条数据
ContentValues values1 = new ContentValues();
values1.put("author", "xianwei");
values1.put("price", 19);
values1.put("pages", 355);
values1.put("name", "悟空传");
database.insert("Book", null, values1);
}
插入数据首先需要获得可读写的数据库对象,然后创建我们要插入的数据,这里我们使用Android提供的一个ContentValues对象来存储数据,这里类的使用特别简单,创建实例对象,然后对应数据库中表的字段,使用put方法存储
SQLiteDatabase database = helper.getWritableDatabase();
最后使用数据库的插入方法将我们创建的数据存储在数据库中
database.insert("Book", null, values1);
有三个参数,第一个参数是表名,第二个参数用于在未指定添加数据的情况下給某些可为空的列自动赋值NULL,一般我们传入null就可以了,第三个参数 就我们刚才创建的数据。
同样我们找到数据库的文件,在DDMS下,导出这个文件,然后使用数据库查看工具查看表中,发现数据以及插入。这样我们就实现数据库的数据添加。
更新数据
添加数据后,我们发现刚才的数据中,有一项值存在问题,现在需要来更改数据,如何做呢?实际上与类似。
/**
* 更新数据
*/
private void update() {
SQLiteDatabase database = helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price", 10.99);
//第一个参数 表名,第二个参数是要替换的值,第三个是要替换哪一个,最后一个指明更新那一个
database.update("Book", values, "name=?", new String[]{"悟空传"});
}
前面的不用说,和上面插入数据一样,这里我们只放入某一项改变后的值,
database.update("Book", values, "name=?", new String[]{"悟空传"});
该方法中,有四个参数,第一个, 表名,第二个,更改后的值,第三个和第四项,共同实现要更改哪一项的值。
通过上述代码,我们就完成了,该条数据的更新,同样可以从DDMS中,将数据库导出,查看是否已经修改了。
删除数据
现在我们来实现删除数据的操作,代码如下
/**
* 删除数据
*/
private void delete() {
SQLiteDatabase database = helper.getWritableDatabase();
//database.delete("Book", "pages>?", new String[]{"300"});
database.delete("Book", null, null);
Log.e(TAG, "大于300的书籍已删除");
}
你会发现删除数据,会特别简单,此时删除的Book,也就是删除调了一整张表。现实中我们很少这样使用,这样很不安全通常我们删除指定数据。
database.delete("Book", "pages>?", new String[]{"300"});
使用条件来限定我们要删除的表中的那条数据。删除数据也已经实现。接下来我们实现数据库中最主要的查询操作。
查询数据
查询一直是数据库中比较复杂的部分,现在简单实现一个查询操作,
query 重载的方法中最少的都有七个参数,
table,column,selection,selectionArgs,groupBy,having,orderBy
突然看见这几个参数,是不是感觉,我擦,这是什么鬼,这么难,不要害怕,这些参数有一些是我们很少使用的
同样我们需要获得可读写或者可读的数据库对象,然后以下代码是查询Book全部数据。
这里通过query可以获取到一个Cursor对象,
/**
* 查询数据,单条
*/
private void queryAll() {
SQLiteDatabase database = helper.getWritableDatabase();
Cursor cursor = database.query("Book", null, null, null, null, null, null);
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getInt(cursor.getColumnIndex("price"));
Log.e(TAG, "name=" + name + " ,author=" + author + ",pages=" + pages + ",price=" + price);
}
cursor.close();//这里需要关闭数据库,是否资源
}
通过遍历这个对象,我们使用以下方法可以获取对应的值。
cursor.getString(cursor.getColumnIndex("name"));
通常的数据的查询,并不是查询全部数据。
使用以下方式来实现查询某条数据
SQLiteDatabase的rawQuery() 用于执行select语句,使用例子如下:
SQLiteDatabase db = ....;
Cursor cursor = db.rawQuery(“select * from person”, null);
while (cursor.moveToNext()) {
int personid = cursor.getInt(0); //获取第一列的值,第一列的索引从0开始
String name = cursor.getString(1);//获取第二列的值
int age = cursor.getInt(2);//获取第三列的值
}
cursor.close();
db.close();
rawQuery()方法的第一个参数为select语句;第二个参数为select语句中占位符参数的值,如果select语句没有使用占位符,该参数可以设置为null。带占位符参数的select语句使用例子如下:
Cursor cursor = db.rawQuery("select * from person where name like ? and age=?", new String[]{"%工工%", "4"});
在上述语句中
Cursor cursor = db.rawQuery("select * from Book where name
like ? and pages>?", new String[]{"%平凡的世界%", "350"});
是模糊查询。其他查询语句也差不多。