根据前面的学习,相信大家都能明白 Android 中 SQLite 数据库是如何创建的,这里我来讲下 SQLite 在 Android 中的数据操作。
数据库表
在我们的 SQLite 数据库中,数据的存储是以表的形式,所以在创建数据库的时候我们也应该创建一张数据表,学习过 SQL 语句的都知道要创建一张完整的数据表,需要表名和列名,而这些事我们有可能要去修改的,所以为了效率,我们应该把这些设置为常量去使用,前面我们建立了一个 Constant 类,让我们添加些数据进去:
public class Constant {
public static final String DATABASE_NAME = "info.db"; //数据库名称
public static final int DATABASE_VERSION = 1; //数据库版本
public static final String TABLE_NAME = "person"; //表名
public static final String _ID = "_id";
public static final String NAME = "name";
public static final String AGE = "age";
}
可以看到,我们又添加了表名和三个字段,这样就方便我们日后修改。
让我们回到 MySQLiteHelper 类:
public void onCreate(SQLiteDatabase db) {
Log.i("TAG", "-------onCreate--------");
String sql = "create table " + Constant.TABLE_NAME + " (" +
Constant._ID + " Integer primary key, " +
Constant.NAME + " varchar(10)," +
Constant.AGE + " Integer)";
db.execSQL(sql);
}
execSQL(String sql) 是 SQLiteDatabase 类的执行 SQL 语句的方法,大家将刚才生成的 info.db 删除,再次运行,这样就能在创建数据库文件的时候创建一张 PERSON 的表啦。
我们把生成的 info.db 导出到桌面或者你自己的某个硬盘目录下,用可视化数据库工具打开,你就可以看到数据库的信息,自然也能看到我们新创建的那张表。
我用的是 Navicat Premium,大家可以从这里下载。
SQL语句增删改查
在 Android 中我们可以自己写 sql 语句去执行,但如果觉得写 sql 语句容易出错,也可以调用 api 中的方法。在 SQLite 中,查询操作是特别的,insert,update,delete都对数据做了修改,但 select 只返回结果,所以我们需要能接收这个结果,这样就不能使用 execSQL 方法啦。
我们还有两个方法可以执行查询,分别是 rawQuery 和 query,query() 是 api 拼接 sql 语句,我们暂且不提。
rawQuery(String sql, String[] selectionArgs),sql 就是执行的 select 语句,selectionArgs 是查询条件的占位符,如果没有占位符,就传入null即可,最后会返回一个 Cursor 对象,帮我们确定数据的位置。
DBManager 类是我们用来管理数据库的工具类,execSQL() 是我们必须用到的方法,为了防止出错,我们应该在 DBManager 类中写个方法来判断,同样 rawQuery() 也应该判断。
public static void execSQL(SQLiteDatabase db, String sql) {
if (db != null) {
if (sql != null && !"".equals(sql)) {
db.execSQL(sql);
}
}
}
public static Cursor selectDataBySql(SQLiteDatabase db, String sql, String[] selectionArgs) {
Cursor cursor = null;
if (db != null) {
cursor = db.rawQuery(sql, selectionArgs);
}
return cursor;
}
相信大家都能够看懂,这里就不讲啦。
rawQuery 是返回一个 Cursor 游标,那么我们自然需要把它转换为熟悉的 list 集合,首先我们要有存储数据的实体类,这就是 Java Bean 思想。
public class Person {
private int _id;
private String name;
private int age;
public Person(int _id, String name, int age) {
this._id = _id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"_id=" + _id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public int get_id() {
return _id;
}
public void set_id(int _id) {
this._id = _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
有了这个 Person 类,我们就可以在 DBManager 中写从 Cursor 中读数据的方法啦。
public static List<Person> cursorTolist(Cursor cursor) {
List<Person> list = new ArrayList<Person>();
while (cursor.moveToNext()) {
//getColumnIndex(String columnName) 根据参数中指定的字段名称获取字段下标
int columnIndex = cursor.getColumnIndex(Constant._ID);
//getInt(int columnIndex)根据参数中指定的字段下标 获取对应int类型的value
int _id = cursor.getInt(columnIndex);
String name = cursor.getString(cursor.getColumnIndex(Constant.NAME));
int age = cursor.getInt(cursor.getColumnIndex(Constant.AGE));
Person person = new Person(_id, name, age);
list.add(person);
}
return list;
}
根据字段名获取字段下标,再得到字段的 value,懂得一点 Cursor 知识的朋友应该都能明白。
public void click(View view) {
switch (view.getId()) {
case R.id.btn_insert :
SQLiteDatabase db = helper.getWritableDatabase();
for (int i = 1; i <= 30; i++) {
String sql1 = " insert into " + Constant.TABLE_NAME + " values(" + i + ",'张三" + i + "'," + i + ") ";
DbManager.execSQL(db, sql1);
}
db.close();
break;
case R.id.btn_update :
db = helper.getWritableDatabase();
String updatesql=" update "+ Constant.TABLE_NAME + " set " + Constant.NAME +
"='xiao' where " + Constant._ID + "=1";
DbManager.execSQL(db,updatesql);
db.close();
break;
case R.id.btn_delete :
db = helper.getWritableDatabase();
String deletesql = " delete from " + Constant.TABLE_NAME + " where " + Constant._ID + "=2";
DbManager.execSQL(db,deletesql);
db.close();
break;
case R.id.btn_query :
db = helper.getWritableDatabase();
String sql = "select * from " + Constant.TABLE_NAME;
Cursor cursor = DbManager.selectDataBySql(db, sql, null);
List<Person> list = DbManager.cursorTolist(cursor);
for (Person p: list) {
Log.i("TAG", p.toString());
}
db.close();
break;
}
}
因为这个代码只是测试数据,所以就随便添加,只要实现功能即可。
这些代码是很容易理解的,现在打开模拟器点击按钮来看看。
我们可以看到表中已经有了30条数据,并且 id = 2的数据已经被删除了,id = 1的数据名字也已经别改成了 xiao,这说明我们的功能已经实现了。这里要注意的是,如果你按了几次 insert,会报错,因为 id 重复了,这并没什么。
因为我们执行的 select 是查询全部信息,所以查询结果也显然成功啦。
API 操作
数据库的增删改查需要正确的 SQL 语句,如果对 SQL 语句不熟练的用提供的 api 也是一样的。
insert
insert(String table, String nullColumnHack, ContentValues values)
table:相信大家都能理解是数据表名。
nullColumnStack:因为在 SQLite 中可以允许列中有 NULL,但不能整列都是NULL,这个值代表强行插入null值的数据列的列名,我们都是给 null 就可以了。
values:代表一行记录的数据。insert 方法插入的一行记录使用ContentValues存放,我们看看它的说明。
private HashMap<String, Object> mValues;
可以知道 ContentValues 是一个键为 String 的 HashMap集合,它提供了多种 put(String key, XXX value) (其中key为数据列的列名)方法用于存入数据,多种 getAsXxx(String key) 方法用于取出数据。
insert 方法返回 long,代表新添记录的行号,该行号是一个内部直,与主键id无关,发生错误返回-1。
update
update(String table, ContentValues values, String whereClause, String[] whereArgs)
table 与 values 和 insert 方法是一样的。
whereClause:表示修改条件,满足该whereClause子句的记录将会被更新。
whereArgs:表示修改条件的占位符,用于为whereArgs子句传递参数。
update 方法返回一个 int,表示修改的数据条数。
delete
delete(String table, String whereClause, String[] whereArgs)
table:代表想删除数据的表名。
whereClause:满足该whereClause子句的记录将会被删除。
whereArgs:用于为whereArgs子句传入参数。
与 update 方法中的格式是一样的。
query
query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
- distinct:指定是否去除重复记录。
- table:执行查询数据的表名。
- columns:要查询出来的列名。
- selection:查询条件子句。
- selectionArgs:用于为selection子句中占位符传入参数值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
- groupBy:用于控制分组。
- having:用于对分组进行过滤。
- orderBy:用于对记录进行排序。
- limit:用于进行分页。
最后返回 Cursor 游标。
public void onClick(View view) {
switch(view.getId()) {
case R.id.btn_insertApi :
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Constant._ID, 2); //put(表示插入数据库的字段名称,表示插入该字段的具体值)
values.put(Constant.NAME, "Lily");
values.put(Constant.AGE, 15);
long result = db.insert(Constant.TABLE_NAME, null, values);
if (result > 0) {
Toast.makeText(this, "插入数据成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "插入数据失败", Toast.LENGTH_SHORT).show();
}
db.close();
break;
case R.id.btn_updateApi :
db = helper.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(Constant.NAME, "cc");//put(表示需要修改的字段名称, 修改后的字段值)
// int count = db.update(Constant.TABLE_NAME, cv, Constant._ID + "=3", null);
int count = db.update(Constant.TABLE_NAME, cv, Constant._ID + "=?", new String[]{"3"});
if (count > 0) {
Toast.makeText(this, "修改数据成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "修改数据失败", Toast.LENGTH_SHORT).show();
}
db.close();
break;
case R.id.btn_deleteApi :
db = helper.getWritableDatabase();
int count2 = db.delete(Constant.TABLE_NAME, Constant._ID + "=?", new String[]{"1"});
if (count2 > 0) {
Toast.makeText(this, "删除数据成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "删除数据失败", Toast.LENGTH_SHORT).show();
}
db.close();
break;
case R.id.btn_queryApi :
db = helper.getWritableDatabase();
Cursor cursor = db.query(Constant.TABLE_NAME, null, Constant._ID + ">?",
new String[]{"10"}, null, null, Constant._ID + " asc");
List<Person> list = DbManager.cursorTolist(cursor);
for (Person p : list) {
Log.i("TAG", p.toString());
}
db.close();
break;
}
}
这可以看到,在写查询条件的时候有两种写法:
db.update(Constant.TABLE_NAME, cv, Constant._ID + "=3", null);
db.update(Constant.TABLE_NAME, cv, Constant._ID + "=?", new String[]{"3"});
这两种是完全一样的。
并没有出现强退,我们看看数据表的变化。
可以看到我们已经删除了 id = 1 的数据,并且以前 id = 2 被删除的数据也插入了新的,id = 3 的数据也被修改了,再看看查询。
id > 10 的数据都被输出了,说明我们 api 的功能也都实现啦。
结束语:本文仅用来学习记录,参考查阅。