简单了解SQLite
百度说:SQLite是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。
SQLiteOpenHelper
SQLiteOpenHelper是Google写好的API,是一个抽象的用于管理数据库创建和版本管理的帮助程序类。
我们要写一个它的子类,这个子类要重写实现onCreate(SQLiteDatabase)
,onUpgrade(SQLiteDatabase, int, int)
并且可选地onOpen(SQLiteDatabase)
,如果数据库存在,则该类负责打开数据库,如果不存在则创建它,并根据需要进行升级。事务用于确保数据库始终处于合理状态。
public class MyOpenHelper extends SQLiteOpenHelper {
//利用SQLiteOpenHelper来创建和获取数据库
public MyOpenHelper(Context context) {
//构造器,若数据库不存在,创建数据库
super(context, "test.db", null, 1);
//第一个参数:上下文
//第二个参数:数据库名称
//第三个参数:游标工厂,一般使用默认的游标,默认值为null
//第四个参数:数据库版本
}
@Override
//在创建数据库的的时候调用onCreate方法,创建新表
public void onCreate(SQLiteDatabase db) {
//创建一张新表
db.execSQL("create table Person(name varchar(20) primary key, sex char(2), age integer); ");
}
@Override
//当更新数据库版本的时候调用onUpgrade方法
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
获取数据库
获取数据库有两个方法:getReadableDatabase() 和 getWritableDatabase(),我们可以看一下Google的介绍
正常情况下,getReadableDatabase() 和 getWritableDatabase() 返回的都是一个SQLiteDatabase类型的数据库,但如果出现了一些问题,如磁盘满了,那么getReadableDatabase()返回的就是一个只读的数据库,而getWritableDatabase()就可能会出现调用错误。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
//new一个db小帮手
MyOpenHelper mOpenHelper = new MyOpenHelper(this);
SQLiteDatabase database = mOpenHelper.getReadableDatabase();
...//要执行的操作
//用完数据库记得要关闭
database.close();
mOpenHelper.close();
}
实现增删改查
获取到数据库database之后就可以直接操作了,一般是调用SQLiteDatabase中的execSQL()的方法。
execSQL(String sql)里的sql是一个完整的sql语句,要注意(“双引号”)和(‘单引号’)的区别,和不要在sql语句最后漏打;分号结束。
(一)插入
插入操作没有返回值
database.execSQL("insert into Person values('张三','男',35);");
database.execSQL("insert into Person values('李四','女',22);");
也可以用Google封装好的API,insert()方法
//为了避免出现"insert into Person(null) values(null)"这种 要插入数据的列为空 而导致程序崩溃的情况
//若将nullColumnHack定为"name"
//这个方法就会将Person(null)中的null改为nullColumnHack的值
String nullColumnHack = "name";
//用ContentValues,通过"列名-列值"的方式来存储要插入的数据
//一个ContentValues对象存储一行的值
ContentValues values = new ContentValues();
//put()方法,第一个参数key,要插入数据的列名,第二个参数value,要插入数据的值
values.put("name","小小");
values.put("sex","女");
values.put("age",10);
//insert()方法返回一个long类型的值,值为插入表中的第几行
long index = database.insert("Person", nullColumnHack, values);
//如果index等于-1,则插入错误,打个提醒
if (index != -1) {
Toast.makeText(this,"完成插入第"+index+"行数据",Toast.LENGTH_SHORT);
}else {
Toast.makeText(this,"插入数据失败",Toast.LENGTH_SHORT);
}
(二)删除
删除操作没有返回值
database.execSQL("delete from Person where name = '李四';");
Google也有封装好的API,delete()方法
//第一个参数:表名
String table = "Person";
//第二个参数:where语句
//注意:=后面的条件要用?代替
String whereClause = "name = ?";
//第三个参数:满足条件的值 用于代替whereClause中的?
String[] whereArgs = {"李四"};
//delete方法会将上面的内容拼成sql语句"delete from Person where name = '李四';" 再执行sql语句
//该方法返回一个整数 删除操作后影响表的行数
int lines = database.delete(table, whereClause, whereArgs);
(三)修改
修改操作没有返回值
database.execSQL("update Person set name = '张三三牛掰' where name = '张三';");
Google的update()方法
//第一个参数:表名
String table = "Person";
//第二个参数:要更新的数据 即放在set后面的内容
ContentValues values = new ContentValues();
values.put("name", "张三三牛掰");
//第三个参数:where语句
//注意:=后面的条件要用?代替
String whereClause = "name = ?";
//第四个参数:一个装着满足条件的值的数组 用于代替whereClause中的?
String[] whereArgs = {"张三"};
//update方法会将上面的内容拼成sql语句"update Person set name = '张三三牛掰' where name = '张三';"
//update方法返回的是修改表后影响的行数
int lines = database.update(table, values, whereClause, whereArgs);
(四)查询
查询操作调用的是rawQuery()方法,并在结果集返回一个游标Cursor,调用Cursor的moveToNext()方法,若有下一行,就返回true值。
Cursor cursor = database.rawQuery("select * from Person;");
while(cursor.moveToNext()){
//当结果集中有下一条,cursor就移到下一条,获取这一行每一列的信息
//每一列的索引从0开始
String name = cursor.getString(0);
//不想数第几列的话也可以通过列名来获取第几列
String sex = cursor.getString(cursor.getColumnIndex("sex"));
int age = cursor.getString(cursor.getColumnIndex("age"));
String info = name+", 性别:"+sex+", 今年"+age+"岁";
Log.d(info, "query: ");
}
Google的query()方法
String table = "Person";
//你要查询的列名 注意:该参数是个字符串数组
String[] columns = {"name","sex"};
//用selectionArgs来代替selection中的?可以防止sql注入攻击
String selection = "sex = ?";
String[] selectionArgs = {"男"};
String groupBy = null;
String having = null;
String orderBy = null;
String limit = null;
//以上条件拼成的sql语句是"select name,sex from Person where sex = '男';"
database.query(table,columns,selection,selectionArgs,groupBy,having,orderBy,limit);
//如果想要查询的语句是"select * from Person;"的话
//表名写好,后面的参数全部写null就可以了
总结
方式 | 有无返回值 | 处理大量数据效率 | 灵活性 | sql出错概率 |
---|---|---|---|---|
execSQL()、rawQuery() | 只有rawQuery()有 | 高 | 高 | 高 |
封装好的API | 都有 | 低 | 低 | 低 |
总体来看呢,自己打出来的sql总体效率会更高,自己想写什么就写什么,可以省去很多步骤,自己写起来也很方便。但自己写的出错率也会高,有时候sql语句不小心写错或者执行出错,程序就会崩溃,用户体验感会下降。
用封装好的API用起来虽然繁琐,但效果会保险很多。
建议是按照自己的需求来选择两种方式。