热度 14
2021-7-26 17:01
2144 次阅读|
0 个评论
在 Android 中,操作 S Q Lite 主要依靠 SQLit e Database 与 SQLiteOpenHelper 这两个类 , 其中 SQLi t eD ata base 是用于执行数据库操作的类, SQLit e OpenHelper 是 SQL i teDatabase 的一个 帮 助类,用来管理数据库的创建和版本的更新。由于 SQLieDatase 对象是通过 SOLiteOpenHel per 调用方法来获得的,因此下面先讲解 SQLite O penHelper 再讲解 SQLiteDatabase 。 1. SQ LiteOpenHelper 为什么需要 SQLiteOpenHelper? 考虑这样一种需求 : 在编写数据库应用软件时,开发 软 件可能会安装在很多用户的手机上,如果应用使用到了 S Q Lite 数据库,就必须在用户初次 使 用软件时创建出应用使用到的数据库表结构并添加一些初始化记录,另外在软件升级的时候 也 需要对数据表结构进行更新。那么,如何才能实现在用户初次使用或升级软件时自动在用户手机上创建出应用需要的数据库表呢 ? 总不能让我们在每个 需 要安装此软件的手机上通过 手 动方式创建数据库表吧 ? 因为这种需求是每个数据库应用都要面临的,所以 Android 系统提 供 了 SQLiteOpenHelper 的抽象类,通过继承它对数据库版本进行管理来实现前面提出的需求。 一个类在继承 SQLiteOpenHelper 时一般需要实现 onCreate 和 onUpgrade 方 法。 S QLi teO penHeper 的主要方法如 下 所示。 SQLiteOpenHelper 类的主要方法 SQ L i t eOpenHe l p e r(Context context,String name,SQLite Data base. C u rsorFactory factory , int version) 构造方法,一般是传递一个要创建的数据库名称的参数 onCreate(SQLiteDatabase db) 创建数据库时调用 o n Up g rade(SQLi t eData ba se db,in oldVersion,it newVersion) 版本更新时调用 get ReadableDatabase() 创建或打开一个只读数据库 g e tWri t a b leDatabase() 创建或打开一个读写数据库 为了实现对数据库版本进行管理, SQLiteOpenHelper 类提供了两个重要的方法,分别是 onCreate(SQLiteDatabase db) 和 onUpgrade ( SQLiteDatabase db , int oldVersion , int newVersion ),前着用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。 当调用 SQLiteOpenHelper 的 getWritableDatabase ()或者 getReadableDatabase ()方法获取用于操作数据库的 SQLiteDatabase 实例时,如果数据库不存在, Android 系统将会自动生成一个数据库,接着调用 onCreate ()方法。 onCreate ()方法在初次生成数据库时才会被调用,在 onCreate ()方法里可以生成数据库表结构并添加一些应用使用到的初始化数据。 onUpgrade ()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是 1 ,由于业务的变更,修改了数据库表结构,这时就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为 2 (可以随意设置,大于 1 即可),并在 o n Up g rade ()方法里面实现表结构的更新。当软件的版本升级次数比较多时,在 onUpgrade ()方 法里 面可以根据原版本号和目标版本号进行判断,然后做出相应的表结构及数据更新。 使用 getWritableDatabase ()和 getReadableDatabase ()方法都可以获取一个用于操作数据库的 S QLiteDa ta base 实例,但 getWritableDatabase () 方法以读写方式打开数据库。一旦数据库的 磁盘 空间满了,数据库就只能读而不能写了如果使用 getWriableDatase () 打开数据库就会出 错, g et Rea d bleDatabase () 方法先以读写方式打开数据库,如果数据库的磁盘空间满了就会 打开失 败,当打开失败后会继续尝试以只读方式打开数据库。所以在这里特别提醒读者, getWritableDatabase ()和 getReadableDatabase ()的区别是,当数据库写满时调用前者会报 错,调用 后者则不会,所以如果不是更新数据库最好调用后者来获得数据库连接。 下 面是一个典型的继承自 SQLiteOpenHelper 的类,读者可以根据上文对 SQLi te Open Helper 的 几 个方法介绍来理解下面的代码。 pubie cla s s Open H e l per extends SQLi t eOpenHe l per { pr i vate s tatic final Sring name=" t est.db";/ 数据库名称 pr i vate s tatic int version=1;/ 数据库版本 public OpenHelper(Context context) { super(context, name,null version ) ; @Over ri de public void onCrea t e(SQLiteDatabase db){ 创建表 db. execSQL("CREATE TABLE IF NOT EXISTS"+ "user(person _ id INTEGER primary key autoincrement,"+"name varchar(32) , age INTEGER)"); @Ove r ride publie void o n Upgrade(SQLiteDatabase db,in oldVersion,int newVersion){ oldVersion)){ // 修改表,加一列 db.execSQL("ALTER TABLE user ADD phone VARCHAR(11)"); }}} 在此特别提醒读者,在 onUpgrade () 方法中要做的是更新表结构等一系列操作,请注意是更新而不是删除后重新创建。试想,在原表中存有大量的用户数据,而该程序将原表删除了,这将会造成多么大的灾难 ! 希望读者能够谨记此点。 2. SQLiteDatabase Android 提供了一个名为 SQLiteDatabase 的类,它封装了一些操作数据库的 API ,使用该类可以完成对数据进行添加( Create )、查询( Retr i eve )、更新( Update )和删除( Delete )操作。 获取 SQLiteDatabase 类的对象要通过 SQLiteOpenHeper 调用 getReadableDatabase () 方法具体如下 ∶ OpenHe lper openHe l per=new Op e nHel p er ( co n text ) ; S QLi te Da ta base db = op e nHelper . getRe a da b leData base() ; 这里的 conext 是 Context 类的对象。当获取了 S QLi te Da ta base 类的对象之后就可以用该 对象 去对数据库进行操作了。官方也为我们提供了很多种操作方法, 比较常用的方法我给大家列出来了。 (int)delete(String table,String whereClause,String whereArgs) 更新数据行的方法 (void)execSQL(String sql) 执行一个 SQL 语句 (void)close() 关闭数据库 (Cursor)query(String table,String args,String groupBy,String having,String orderBy,String limit) 查询指定的数据表返回一个带游标的数据集 (Cursor)rawQuery(String sql,String s e l e ctionArgs )来实现 ; 另外一种就是通过调用系统的 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 )方法 , k e y 为字段名称, value 为字段值, Xxx 指的是各种常用的数据类型,如 String 、 Integer 等。使用范例如下 ∶ ContentValues contentValues=new ContentValues ( ) content V alues.put ( "nane" , " 大鸟科创空间 " ) ; contentValues .put("age ” , 5 ); db. i n ser t ("user", n ull,contentValues); d b. Cl ose () ; 在上述 范例代码中,不管 inser t() 的第三个参数是否包含数据,执行 insert () 方法必然会添加一条记录,如果第三个参数为空就会添加一条除主键之外其他字段值为 null 的记录 。 Insert() 方法内部实际上通过构造 insert SQL 语 句完成了数据的添加。 不 管 第 三个参 数 是 否 包含数据 , 执行 insert () 方法必然会添加一条记录,如果第三个参为空,会添加一条除主键之外其他字段值为 null 的记录 。 Insert () 方法内部实际上通过构造 insert SQL 语句完成数据 的 添加, Insert ()方法的 第二个参数用于指定空值字段的名称,相信大家该参数会感到疑感,该参数的作用是如 果 第三个参数 vaues 为 nu ll 或者 元 素个数为 0 , 由 于 Insert () 方法要求必须添效一条除了主键之外其他字段为 nul 值的 记录 ,为了满足 SQL 语的需要, inse rt 语 句 必须给定一个 字 段名,如 i n se rt i n to person ( name ) values ( n ull ),倘若不给字段名, inser t 语句变为 in s er t into person () values ( n ull ),显然不满足标准 SQL 的语法。对于字段名,建议使用主键之外的字段,如果使用了 I NTEGER 类型的主键字段,执行类似 insert i nto person(personid) values(null) 的 i n ser t 语句后,该主键字段值也不会为 null 。如果第三个参数 values 不为 nul 并且元素的个数大于 0 ,就把第二个参数设置为 null 。 另外, imser t() 是有返回值的 ∶ 当执行失败时会返回 -1 ,其他时候返回新添加记录的行号 , 开发时可以据此判断是否添加成功。 ( 2 )删除数据 Delete ( S t ring t able , S t ring whereClause , Sring {"12"); db. cl os e (); 范例的意义是删除 user 表中 id=12 的数据。 delete ()方法也是有返回值的,它的返回值指的是删除操作影响的行数,如果返回值为 0 就意味着操作失败。开发时可以据此判断是否删除成功。 ( 3 )更新操作 Update ( S t ring table , ContentValues values , S t ring whereClause , 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 语句一样, 除了表名不可为空外,都可以为空。 查询所有数据的范例如下 ∶ p ublic Lis t queryA l l ( ) { Lis t userList=newAr r ayLis t() ; Cursor cursor=db.query("user" , null , nu l l, null , null , null , null); while(cursor . moveToNext () ) { User user=new User ( ); u ser . set U ser I d (cursor.getInt (0) ) ; u ser . s e tName (cursor.getString(1 ) ) ; User . setAge ( cursor . getlnt ( 2 ) ); user L ist .ad d(user); } re t urn u serlis t; } 查询指定数据的范例如下 ∶ pub lic User queryOnet ( User use r ){ Cursor c ur s or=d b.query (" u ser",nu l l,"na m e=?", new String [] {user . ge t Name ( ) } , n u ll , n ull, nu ll ) ; wh i le (c urso r. moveToNext () ) { User . setUserld(curso r. getIn t (0 )) ; User . setAge(cursor.getInt(2)); } return us er ; }