在 Android 中,操作SQLite主要依靠SQLiteDatabase与 SQLiteOpenHelper 这两个类,其中 SQLiteDatabase 是用于执行数据库操作的类,SQLiteOpenHelper 是 SQLiteDatabase 的一个帮助类,用来管理数据库的创建和版本的更新。由于 SQLieDatase 对象是通过 SOLiteOpenHelper调用方法来获得的,因此下面先讲解SQLiteOpenHelper 再讲解 SQLiteDatabase。
1. SQLiteOpenHelper
为什么需要 SQLiteOpenHelper?考虑这样一种需求:在编写数据库应用软件时,开发软件可能会安装在很多用户的手机上,如果应用使用到了 SQLite数据库,就必须在用户初次使用软件时创建出应用使用到的数据库表结构并添加一些初始化记录,另外在软件升级的时候也需要对数据表结构进行更新。那么,如何才能实现在用户初次使用或升级软件时自动在用户手机上创建出应用需要的数据库表呢?总不能让我们在每个需要安装此软件的手机上通过手动方式创建数据库表吧?因为这种需求是每个数据库应用都要面临的,所以Android系统提供了SQLiteOpenHelper的抽象类,通过继承它对数据库版本进行管理来实现前面提出的需求。
一个类在继承 SQLiteOpenHelper 时一般需要实现 onCreate 和 onUpgrade 方法。SQLiteOpenHeper 的主要方法如下所示。
SQLiteOpenHelper类的主要方法
SQLiteOpenHelper(Context context,String name,SQLite Database.CursorFactory factory, int version) 构造方法,一般是传递一个要创建的数据库名称的参数
onCreate(SQLiteDatabase db) 创建数据库时调用
onUpgrade(SQLiteDatabase db,in oldVersion,it newVersion) 版本更新时调用
getReadableDatabase() 创建或打开一个只读数据库
getWritableDatabase() 创建或打开一个读写数据库
为了实现对数据库版本进行管理,SQLiteOpenHelper 类提供了两个重要的方法,分别是 onCreate(SQLiteDatabase db) 和 onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion),前着用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。
当调用 SQLiteOpenHelper 的 getWritableDatabase()或者 getReadableDatabase()方法获取用于操作数据库的 SQLiteDatabase 实例时,如果数据库不存在,Android 系统将会自动生成一个数据库,接着调用 onCreate()方法。onCreate()方法在初次生成数据库时才会被调用,在 onCreate()方法里可以生成数据库表结构并添加一些应用使用到的初始化数据。
onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为 2(可以随意设置,大于 1 即可),并在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多时,在 onUpgrade()方法里面可以根据原版本号和目标版本号进行判断,然后做出相应的表结构及数据更新。
使用 getWritableDatabase()和 getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase 实例,但 getWritableDatabase()方法以读写方式打开数据库。一旦数据库的磁盘空间满了,数据库就只能读而不能写了如果使用 getWriableDatase()打开数据库就会出错, getReadbleDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。所以在这里特别提醒读者, getWritableDatabase()和 getReadableDatabase()的区别是,当数据库写满时调用前者会报错,调用后者则不会,所以如果不是更新数据库最好调用后者来获得数据库连接。
下面是一个典型的继承自SQLiteOpenHelper的类,读者可以根据上文对SQLiteOpenHelper的几个方法介绍来理解下面的代码。
pubie class OpenHelper extends SQLiteOpenHelper {
private static final Sring name="test.db";/数据库名称
private static int version=1;/数据库版本
public OpenHelper(Context context) {
super(context, name,null version);
@Override
public void onCreate(SQLiteDatabase db){
创建表
db.execSQL("CREATE TABLE IF NOT EXISTS"+
"user(person_id INTEGER primary key autoincrement,"+"name varchar(32), age INTEGER)");
@Override
publie void onUpgrade(SQLiteDatabase db,in oldVersion,int newVersion){
if(newVersion> oldVersion)){
//修改表,加一列
db.execSQL("ALTER TABLE user ADD phone VARCHAR(11)");}}}
在此特别提醒读者,在 onUpgrade()方法中要做的是更新表结构等一系列操作,请注意是更新而不是删除后重新创建。试想,在原表中存有大量的用户数据,而该程序将原表删除了,这将会造成多么大的灾难!希望读者能够谨记此点。
2. SQLiteDatabase
Android提供了一个名为SQLiteDatabase 的类,它封装了一些操作数据库的 API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)操作。
获取 SQLiteDatabase类的对象要通过 SQLiteOpenHeper 调用getReadableDatabase()方法具体如下∶
OpenHelper openHelper=new OpenHelper(context);
SQLiteDatabase db=openHelper.getReadableDatabase();
这里的conext 是 Context类的对象。当获取了SQLiteDatabase类的对象之后就可以用该对象去对数据库进行操作了。官方也为我们提供了很多种操作方法,比较常用的方法我给大家列出来了。
(int)delete(String table,String whereClause,String[] whereArgs) 删除数据行的方法
(long)insert(String table,String nullColumnHack,ContentValues values) 添加数据行的方法
(int)update(String table,ContentValues values,String whereClause,String[] whereArgs) 更新数据行的方法
(void)execSQL(String sql) 执行一个SQL 语句
(void)close() 关闭数据库
(Cursor)query(String table,String[] columns,String selection,String[] args,String groupBy,String having,String orderBy,String limit)查询指定的数据表返回一个带游标的数据集
(Cursor)rawQuery(String sql,String[] args) 运行一个预置的 SQL 语句,返回带游标的数据集,与execSQL(String sql)相比,它可以防止 SQL注入
从这几个实例中我们发现增、删、改、查的操作都可以通过两种方式来实现:第一种是通过手动编写 SQL 语句、调用 execSQL(String sql)以及 rawQuery(String sql,String[] selectionArgs)来实现;另外一种就是通过调用系统的 insert()、delete()、update()和query()等api来实现。官方提供的这些api是通过开发者传入的参数进行 SQL 的组装,而 Google公司这些工程师根据传入的参数写出的 SQL 在执行效率等各个方面都是相对高效的,并且在 SQL 语句的格式上也是统一的,使用这些 api可能甚至比一些精通 SQL 的开发者使用第一种方式要好。除之外,api 的统一性很好,在代码的可读性以及维护性上的优势是不可小视的。因此,这里建议使用官方提供的 api进行数据库的操作,具体如下。
(1)增加数据
insert(String table,String nullColumnHack,ContentValues values)方法用于添加数据,各个字段的数据使用 ContentValues 进行存放。ContentValues 类似于 MAP。相对于 MAP, ContentValues 提供了存取数据对应的 put(String key,Xxx value)和getAsXxx(String key)方法,key为字段名称,value为字段值,Xxx指的是各种常用的数据类型,如 String、Integer等。使用范例如下∶
ContentValues contentValues=new ContentValues()
contentValues.put("nane","大鸟科创空间");
contentValues .put("age”,5);
db.insert("user",null,contentValues);
db. Close();
在上述范例代码中,不管 insert()的第三个参数是否包含数据,执行 insert()方法必然会添加一条记录,如果第三个参数为空就会添加一条除主键之外其他字段值为null的记录。Insert()方法内部实际上通过构造insert SQL 语句完成了数据的添加。
不管第三个参数是否包含数据,执行insert()方法必然会添加一条记录,如果第三个参为空,会添加一条除主键之外其他字段值为null的记录。Insert()方法内部实际上通过构造 insert SQL 语句完成数据的添加,Insert()方法的第二个参数用于指定空值字段的名称,相信大家该参数会感到疑感,该参数的作用是如果第三个参数vaues为null或者元素个数为0,由于Insert()方法要求必须添效一条除了主键之外其他字段为nul值的记录,为了满足 SQL语的需要,insert语句必须给定一个字段名,如 insert into person(name)values(null),倘若不给字段名,insert语句变为 insert into person()values(null),显然不满足标准SQL的语法。对于字段名,建议使用主键之外的字段,如果使用了 INTEGER类型的主键字段,执行类似 insert into person(personid) values(null)的 insert 语句后,该主键字段值也不会为 null。如果第三个参数 values 不为nul并且元素的个数大于0,就把第二个参数设置为 null。
另外,imsert()是有返回值的∶当执行失败时会返回-1,其他时候返回新添加记录的行号,开发时可以据此判断是否添加成功。
(2)删除数据
Delete(String table,String whereClause,Sring[] whereArgs)方法共有3个参数,第一个参数表示的是要执行操作的表,第二个参数用来过滤不需要的值或者选择适当的要素,第三个参数用于给第二个参数的占位符提供数据,其中第二个参数可以有多个条件。具体的范例如下;
db.delete("user","id=?",new String[]{"12");
db.close();
范例的意义是删除 user 表中id=12 的数据。delete()方法也是有返回值的,它的返回值指的是删除操作影响的行数,如果返回值为0就意味着操作失败。开发时可以据此判断是否删除成功。
(3)更新操作
Update(String table,ContentValues values,String whereClause,String[]whereArgs)方法共有4个参数,第一个参数表示的是要执行操作的表,第二个参数使用一个 ContentValues 对象封装要更新的列和对应的值,第三个参数用来过滤不需要的值或者选择适当的要素,第四个参数用于给第二个参数的占位符提供数据,其中第三个参数可以有多个条件。具体的范例如下;
ContentValues contentValues=new ContentValues();
contentValues.put"name","大鸟科创空间");
contentValues.put("age",5);
db.update("user",contentValues,"id=?",new String[{"12"});
范例的意义是将user表中id=12的数据的 name修改为"大鸟科创空间",age 修改为5。Update()方法也是有返回值的,它的返回值指的是更新操作影响的行数,如果返回值为 0就意味着操作失败。开发时可以据此判断是否更新成功。
(4)查询操作
由于查询操作的返回值是Cursor类的对象,因此在介绍查询操作之前要介绍Cusor类 。Android系统中,数据库查询结果的返回值并不是数据集合的完整复制,而是返回数据集的指针,这个指针就是Cursor类。Cursor类支持在查询的数据集合中的多种移动方式,并能够按取数据集合的属性名称和序号。针对Cursor,系统提供了一些操作方法,如下图所示:
getGount() 总记录条数
isFirst() 判断是否为第一条记录
isLast() 判断是否为最后一条记录
moveToFirst() 移动到第一条记录
moveToLast() 移动到最后一条记录
move(int offset) 移动到指定的记录
moveToNext 移动到下一条记录
moveToPrevious() 移动到上一条记录
getColumnIndex(String columnName) 获得指定列索引的 int类型值
查询操作相对前面几种操作要复杂一些,因为查询会带有很多条件。查询操作的方法 query(String table,String[] columns, String selection,String[] selectionArgs,String groupBy, String having,String orderBy,String limit)共有8个参数。这些参数的意义如下∶
● table∶ 表名称,不可为空。
● colums∶ 想要查询的字段名称数组,可以为 null,如果为 null就返回所有字段
● selection∶ 条件子句,相当于SQL语句中的 where部分,可以为空,为空时则查询所有数据·
● selecionArgs∶ 条件语句的参数数组,用来填充到条件子句的占位符中,当然也可以为空。
● groupBy∶ 分组语句,可以为空。
● having∶ 分组条件,可以为空。
● orderBy∶ 用来排序的语句,可以为空。
● limit用来做分页查询的限制条件,可以为空。
读者可以发现 query()方法的8个参数其实对应着SQL 语句的各个部分,也和 SQL语句一样, 除了表名不可为空外,都可以为空。
查询所有数据的范例如下∶
public ListqueryAll()
{
ListuserList=newArrayList();
Cursor cursor=db.query("user",null,null, null,null,null,null);
while(cursor.moveToNext()){
User user=new User();
user.setUserId(cursor.getInt(0));
user.setName(cursor.getString(1));
User.setAge(cursor.getlnt(2));
userList.add(user);
}
return userlist;
}
查询指定数据的范例如下∶
public User queryOnet(User user){
Cursor cursor=db.query("user",null,"name=?", new String[]{user.getName()},null, null,null);
while (cursor.moveToNext()){
User.setUserld(cursor.getInt(0));
User.setAge(cursor.getInt(2));
}
return user;
}
作者: 大鸟科创空间, 来源:面包板社区
链接: https://mbb.eet-china.com/blog/uid-me-3949041.html
版权声明:本文为博主原创,未经本人允许,禁止转载!
文章评论(0条评论)
登录后参与讨论