上次我向大家介紹了SQLite的基本信息和使用過(guò)程,相信朋友們對(duì)SQLite已經(jīng)有所了解了,那今天呢,我就和大家分享一下在Android中如何使用SQLite。
現(xiàn)在的主流移動(dòng)設(shè)備像Android、iPhone等都使用SQLite作為復(fù)雜數(shù)據(jù)的存儲(chǔ)引擎,在我們?yōu)橐苿?dòng)設(shè)備開(kāi)發(fā)應(yīng)用程序時(shí),也許就要使用到SQLite來(lái)存儲(chǔ)我們大量的數(shù)據(jù),所以我們就需要掌握移動(dòng)設(shè)備上的SQLite開(kāi)發(fā)技巧。對(duì)于Android平臺(tái)來(lái)說(shuō),系統(tǒng)內(nèi)置了豐富的API來(lái)供開(kāi)發(fā)人員操作SQLite,我們可以輕松的完成對(duì)數(shù)據(jù)的存取。
一 、SQLiteOpenHelper
可以直接使用SQLiteDataBase直接去創(chuàng)建數(shù)據(jù)庫(kù),但是Android提供了一種更加安全優(yōu)雅的方式去操作數(shù)據(jù)庫(kù),那就是SQLiteOpenHelper。SQLiteOpenHelper是用來(lái)管理數(shù)據(jù)庫(kù)的一個(gè)工具類(lèi),可以用于管理數(shù)據(jù)庫(kù)的創(chuàng)建和版本更新。
SQLiteOpenHelper是一個(gè)抽象類(lèi),所以要?jiǎng)?chuàng)建它的子類(lèi),重寫(xiě)它的方法來(lái)使用它創(chuàng)建和管理數(shù)據(jù)庫(kù)。
子類(lèi)繼承SQLiteOpenHelper的方法,必須重寫(xiě)下面兩個(gè)方法:
1 | public abstract void onCreate(SQliteDatabase db); |
2 | public abstract void onUpdate(SQLiteDatabase db,int oldVersion,int newVersion); |
SQLiteOpenHelper會(huì)自動(dòng)檢測(cè)數(shù)據(jù)庫(kù)文件是否存在。如果存在,會(huì)打開(kāi)這個(gè)數(shù)據(jù)庫(kù),在這種情況下就不會(huì)調(diào)用onCreate()方法。如果數(shù)據(jù)庫(kù)文件不存在,SQLiteOpenHelper首先會(huì)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)文件,然后打開(kāi)這個(gè)數(shù)據(jù)庫(kù),最后調(diào)用onCreate()方法。因此,onCreate()方法一般用來(lái)在新創(chuàng)建的數(shù)據(jù)庫(kù)中建立表、視圖等數(shù)據(jù)庫(kù)組建。也就是說(shuō)oncreate()方法在數(shù)據(jù)庫(kù)文件第一次創(chuàng)建時(shí)調(diào)用。
先看看SQLiteOpenHelper類(lèi)的構(gòu)造方法再解釋onUpdate()方法何時(shí)會(huì)被調(diào)用。
public SQLiteOpenHelper(Context context,String name,CursorFactory factory,int version);
其中name參數(shù)表示數(shù)據(jù)庫(kù)文件名(不包括文件路徑),SQLiteOpenHelper會(huì)根據(jù)這個(gè)文件名創(chuàng)建數(shù)據(jù)庫(kù)文件。version表示數(shù)據(jù)庫(kù)的版本號(hào)。如果當(dāng)前傳入的數(shù)據(jù)庫(kù)版本號(hào)比上次創(chuàng)建或升級(jí)的版本號(hào)高,SQLiteOpenHelper就會(huì)調(diào)用onUpdate()方法。也就是說(shuō),當(dāng)數(shù)據(jù)庫(kù)第一次創(chuàng)建時(shí)會(huì)有一個(gè)初始的版本號(hào)。當(dāng)需要對(duì)數(shù)據(jù)庫(kù)中的表、視圖等組建升級(jí)時(shí)可以增大版本號(hào),再重新創(chuàng)建它們?,F(xiàn)在總結(jié)一下oncreate()和onUpdate()調(diào)用過(guò)程。
1.如果數(shù)據(jù)庫(kù)文件不存在,SQLiteOpenHelper在自動(dòng)創(chuàng)建數(shù)據(jù)庫(kù)后會(huì)調(diào)用oncreate()方法,在該方法中一般需要?jiǎng)?chuàng)建表、視圖等組件。在創(chuàng)建前數(shù)據(jù)庫(kù)一般是空的,因此不需要先刪除數(shù)據(jù)庫(kù)中相關(guān)的組件。
2.如果數(shù)據(jù)庫(kù)文件存在,并且當(dāng)前版本號(hào)高于上次創(chuàng)建或升級(jí)的版本號(hào),SQLiteOpenHelper會(huì)調(diào)用onUpdate()方法,調(diào)用該方法后會(huì)更新數(shù)據(jù)庫(kù)的版本號(hào)。在onupdate()方法中除了創(chuàng)建表、視圖等組件外,還需要先刪除這些相關(guān)的組件,因此,在調(diào)用onupdate()方法前,數(shù)據(jù)庫(kù)是存在的,里面還原許多數(shù)據(jù)庫(kù)組建。
綜合上述兩點(diǎn),可以得出一個(gè)結(jié)論。如果數(shù)據(jù)庫(kù)文件不存在,只有oncreate()被調(diào)用(該方法在創(chuàng)建數(shù)據(jù)庫(kù)時(shí)被調(diào)用一次)。如果數(shù)據(jù)庫(kù)文件存在,會(huì)調(diào)用onupdate()方法升級(jí)數(shù)據(jù)庫(kù),并更新版本號(hào)。
除了必須重寫(xiě)這兩個(gè)方法外,還必須要一個(gè)構(gòu)造方法:
SQLiteOpenHelper提供了兩個(gè)構(gòu)造方法:
1、public SQLiteOpenHelper(Context context,String name, SQLiteDatabase.CursorFactory factory, int version)
創(chuàng)建一個(gè)helper對(duì)象,用于管理數(shù)據(jù)庫(kù)。
參數(shù):
context : Context對(duì)象,用于去打開(kāi)或創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)
name : 數(shù)據(jù)庫(kù)名稱(chēng)
factory : 游標(biāo)工廠,用于創(chuàng)建一個(gè)游標(biāo)對(duì)象,如果使用null,則使用默認(rèn)的游標(biāo)
version : 數(shù)據(jù)庫(kù)版本號(hào),從1開(kāi)始。如過(guò)版本號(hào)提升了,那么就去調(diào)用onUpgrade(SQLiteDatabase, int, int)方法。如過(guò)版本號(hào)降低了,那么就去調(diào)用onDowngrade(SQLiteDatabase, int, int)方法。
2、public SQLiteOpenHelper(Context context,String name, SQLiteDatabase.CursorFactory factory, int version,DatabaseErrorHandler errorHandler)
創(chuàng)建一個(gè)helper對(duì)象,用于管理數(shù)據(jù)庫(kù)。
參數(shù):
context : Context對(duì)象,用于去打開(kāi)或創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)
name : 數(shù)據(jù)庫(kù)名稱(chēng)
factory : 游標(biāo)工廠,用于創(chuàng)建一個(gè)游標(biāo)對(duì)象,如果使用null,則使用默認(rèn)的游標(biāo)
version : 數(shù)據(jù)庫(kù)版本號(hào),從1開(kāi)始。如過(guò)版本號(hào)提升了,那么就去調(diào)用onUpgrade(SQLiteDatabase, int, int)方法。如過(guò)版本號(hào)降低了,那么就去調(diào)用onDowngrade(SQLiteDatabase, int, int)方法。
errorHandler :用于報(bào)告數(shù)據(jù)庫(kù)
SQLiteOpenHelper類(lèi)當(dāng)然還有其他的方法,不過(guò)一般不需要我們?nèi)ブ貙?xiě)。
public synchronized void close() :關(guān)閉任何已經(jīng)打開(kāi)的數(shù)據(jù)庫(kù)。
public String getDatabaseName() :返回打開(kāi)的數(shù)據(jù)庫(kù)的名稱(chēng),就是構(gòu)造器指定的那個(gè)數(shù)據(jù)庫(kù)。
public synchronized SQLiteDatabase getReadableDatabase() :打開(kāi)或者創(chuàng)建一個(gè)只讀的數(shù)據(jù)庫(kù)
public synchronized SQLiteDatabase getWriteableDatabase() :打開(kāi)或者創(chuàng)建一個(gè)可讀寫(xiě)的數(shù)據(jù)庫(kù)
public void onDowngrade(SQLiteDadabase db,int oldVersion,int newVersion) :數(shù)據(jù)庫(kù)版本號(hào)降低時(shí)調(diào)用
public void onOpen(SQLiteDatabase db) :數(shù)據(jù)庫(kù)打開(kāi)時(shí)調(diào)用
如何使用SQLiteOpenHelper的子類(lèi),去創(chuàng)建和管理數(shù)據(jù)庫(kù):
1、使用構(gòu)造方法new一個(gè)helper對(duì)象
2、使用helper對(duì)象,調(diào)用getReadableDatabase()或getWriteableDatabase()方法返回一個(gè)SQLiteDatabase對(duì)象
3、使用SQLiteDatabase對(duì)象進(jìn)行數(shù)據(jù)庫(kù)操作。
舉個(gè)簡(jiǎn)單的例子:
[html] view plaincopy
01 | public class DBHelper extends SQLiteOpenHelper { |
03 | private static final String DATABASE_NAME = "test.db"; |
04 | private static final int DATABASE_VERSION = 1; |
06 | public DBHelper(Context context) { |
07 | //CursorFactory設(shè)置為null,使用默認(rèn)值 |
08 | super(context, DATABASE_NAME, null, DATABASE_VERSION); |
11 | //數(shù)據(jù)庫(kù)第一次被創(chuàng)建時(shí)onCreate會(huì)被調(diào)用 |
13 | public void onCreate(SQLiteDatabase db) { |
14 | db.execSQL("CREATE TABLE IF NOT EXISTS person" + |
15 | "(_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age INTEGER, info TEXT)"); |
18 | //如果DATABASE_VERSION值被改為2,系統(tǒng)發(fā)現(xiàn)現(xiàn)有數(shù)據(jù)庫(kù)版本不同,即會(huì)調(diào)用onUpgrade |
20 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { |
21 | db.execSQL("ALTER TABLE person ADD COLUMN other STRING"); |
二 、SQLiteDatabase
SQLiteDatabase對(duì)象,代表的就是一個(gè)數(shù)據(jù)庫(kù)(底層就是一個(gè)數(shù)據(jù)庫(kù)文件)。我們可以調(diào)用SQLiteDatabase累的幾個(gè)靜態(tài)方法,來(lái)獲得一個(gè)數(shù)據(jù)庫(kù)對(duì)象。當(dāng)然,更好的方法是上面介紹的,使用SQLiteOpenHelper的子類(lèi)來(lái)獲得一個(gè)SQLiteDatabase對(duì)象。
當(dāng)然,不管以什么方式獲得了SQLiteDatabase對(duì)象之后,我們就可以進(jìn)行數(shù)據(jù)庫(kù)的操作。大部分操作都類(lèi)似于jdbc中的操作,很容易理解。
數(shù)據(jù)庫(kù)的操作無(wú)非CURD,對(duì)于 增 刪 改這三種情況,我們可以直接使用
1 | public void execSQL (String sql) |
2 | public void execSQL (String sql, Object[] bindArgs) |
這兩種方法,直接執(zhí)行標(biāo)準(zhǔn)的SQL語(yǔ)句,也可以用特定的方法來(lái)實(shí)現(xiàn),不過(guò)對(duì)于熟悉SQL語(yǔ)言的人來(lái)說(shuō),還是使用前一種方法比較直接。
至于查詢(xún)情況,就要復(fù)雜一點(diǎn),我們也可以直接使用
public Cursor rawQuery(String sql,String[] selectionArgs)
方法,直接執(zhí)行標(biāo)準(zhǔn)的SQL查詢(xún)語(yǔ)句。當(dāng)然,和增刪改一樣,也可以用特定的方法來(lái)實(shí)現(xiàn)。
不對(duì)用什么方法進(jìn)行查詢(xún),都會(huì)將結(jié)果集作為一個(gè)Cursor游標(biāo)對(duì)象返回。Cursor對(duì)象類(lèi)是以jdbc中的ResultSet對(duì)象。
下面是Cursor對(duì)象的常用方法:
[html] view plaincopy
01 | //假設(shè)c是一個(gè)返回的Cursor對(duì)象 |
02 | c.move(int offset); //以當(dāng)前位置為參考,移動(dòng)到指定行 |
03 | c.moveToFirst(); //移動(dòng)到第一行 |
04 | c.moveToLast(); //移動(dòng)到最后一行 |
05 | c.moveToPosition(int position); //移動(dòng)到指定行 |
06 | c.moveToPrevious(); //移動(dòng)到前一行 |
07 | c.moveToNext(); //移動(dòng)到下一行 |
10 | c.isBeforeFirst(); //是否指向第一條之前 |
11 | c.isAfterLast(); //是否指向最后一條之后 |
12 | c.isNull(int columnIndex); //指定列是否為空(列基數(shù)為0) |
13 | c.isClosed(); //游標(biāo)是否已關(guān)閉 |
14 | c.getCount(); //總數(shù)據(jù)項(xiàng)數(shù) |
15 | c.getPosition(); //返回當(dāng)前游標(biāo)所指向的行數(shù) |
16 | c.getColumnIndex(String columnName);//返回某列名對(duì)應(yīng)的列索引值 |
17 | c.getString(int columnIndex); //返回當(dāng)前行指定列的值 string類(lèi)型 |
18 | p; c.getInt(int columnIndex); //返回當(dāng)前行指定列的值 int類(lèi)型 |
19 | c.getFloat(int columnIndex); //返回當(dāng)前行指定列的值 float類(lèi)型 |
關(guān)于更多的Cursor信息,可以參考官方文檔中的說(shuō)明。要想熟練的使用,還是得多多練習(xí)。
三、事務(wù)的概念
SQLite數(shù)據(jù)庫(kù)也使用了事務(wù)的處理方法,SQLiteDatabase類(lèi)也提供了事務(wù)處理的API。
使用beginTransaction()方法開(kāi)啟一個(gè)事務(wù),然后執(zhí)行數(shù)據(jù)庫(kù)操作,然后調(diào)用setTransactionSuccessful()方法設(shè)置事務(wù)成功標(biāo)志。使用endTransaction結(jié)束提交事務(wù)。
還可以使用inTransaction()方法判斷是否處于一個(gè)事務(wù)中。
下面幾個(gè)例子說(shuō)明:
[html] view plaincopy
03 | SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); |
05 | db.beginTransaction(); |
08 | //執(zhí)行數(shù)據(jù)庫(kù)操作 |
09 | db.execSQL("update person set amount=amount-10 where personid=?", new Object[]{1}); |
10 | db.execSQL("update person set amount=amount+10 where personid=?", new Object[]{2}); |
11 | //設(shè)置事務(wù)標(biāo)志為成功,當(dāng)結(jié)束事務(wù)時(shí)就會(huì)提交事務(wù) |
12 | db.setTransactionSuccessful(); |
最后:關(guān)于SQLiteDatabase的使用流程基本介紹完了,下面在介紹SQLite中數(shù)據(jù)庫(kù)的操作和數(shù)據(jù)集返回如何處理。
|