Android開發(fā)學習教程(31)- Android SQLite使用教程
—— 不為跑贏世界,只為超越自己。
Android提供了四種不同的方式用于本地數據庫,我們可以說它是一個關系數據庫。Android 系統(tǒng)有內部已經實現了CRUD(android.sqlite?包中提供了一組可用的類。
在使用 SQLite 時,可能有兩種不同的方式來執(zhí)行不同的操作如創(chuàng)建、讀取、更新和刪除。一種是編寫原始SQL語句,另一種是使用參數化函數,或者我們可以說是參數化查詢。
創(chuàng)建數據庫
使用 SQLiteOpenHelper 類在 Android 中創(chuàng)建數據庫非常簡單。SQLiteOpenHelper 是一個抽象類,具有兩個抽象方法 onCreate(SQLiteDatabase?int?oldVersion, int newVersion) 以及更多對數據庫有用的函數。每當我們需要創(chuàng)建數據庫時,我們必須擴展 SQLiteOpenHelper 類,如下所示:
static
?final
?String DATABASE_NAME =?
"test.db"
;
????
public
?static
?final
?int
?version =?
1
;
?????
????
public
?SqliteManager(Context?<a href="https://yunjunet.cn/tag/context" context"target="_blank" style="color: rgb(102, 102, 102); cursor: pointer; transition: all 0.3s ease 0s;">context) {
???????
super
(context, DATABASE_NAME,?
null
, version);
????
}
????
@Override
????
public
?void
?onCreate(SQLiteDatabase sqLiteDatabase) {
???????
String dbQuery =?
"CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT, description TEXT)"
;
???????
sqLiteDatabase.execSQL(dbQuery);
????
}
????
@Override
????
public
?void
?onUpgrade(SQLiteDatabase sqLiteDatabase,?
int
?oldVersion,?
int
?newVersion) {
????????
????
}
????
}
onCreate(SQLiteDatabase sqLiteDatabase)方法在整個應用程序生命周期中只調用一次,每當第一次調用 SQLiteOpenHelper 類中的 getReadableDatabase() 或 getWritableDatabase() 函數時都會調用它,因此 SQLiteOpenHelper 類在創(chuàng)建后調用 onCreate() 方法數據庫并實例化 SQLiteDatabase 對象。數據庫名稱在構造函數調用中傳遞。
onUpgrade(SQLiteDatabase db,int oldVersion, int newVersion)僅在升級APP版本并且數據庫有更新時調用,因此需要更新版本時我們必須增加version的值,比如app從1.0.0升級到1.0.1的時候數據庫需要升級的話,對應的version就要改成大于1的任何整數即可。在 onUpgrade 方法中,我們可以編寫SQL語句來執(zhí)行所需的任何操作。如增加一張新表,增加一條數據記錄等等。
在 Sqlite 中插入、讀取、刪除和更新操作
執(zhí)行插入、讀取、刪除、更新操作有兩種不同的方式:
1. 編寫參數化查詢(推薦)
2. 編寫原始SQL語句
參數化查詢:這些查詢使用SDK內置的函數來插入、讀取、刪除或更新數據。這些操作相關的函數在 SQLiteDatabase 類中提供。
原始SQL語句:這些是類似于 MySql、Sql Server 等其他數據庫的 sql 查詢語句,將這些SQL語句當做參數傳給 rawQuery(String sql,String [] selectionArgs) 或 execSQL(String sql,Object [] bindArgs) 方法來執(zhí)行操作。
注: Android 官方不建議使用原始SQL語句來執(zhí)行插入、讀取、更新、刪除操作,建議始終使用 SQLiteDatabase 類的內置函數執(zhí)行插入、查詢、更新、刪除操作。原因如下:
當使用原始SQL語句執(zhí)行插入操作的時:
public
?void
?insertItem(Item item) {
????
String query =?
"INSERT INTO "
?+ ItemTable.NAME +?
" VALUES (0,?,?)"
;
????
SQLiteDatabase db = getWritableDatabase();
????
db.execSQL(query,?
new
?String[]{item.name, item.description});
????
db.close();
}
在使用原始查詢時,我們永遠不會知道操作的結果,即db.execSQL的返回值是void類型。而使用參數化查詢函數則會返回一個值來表示操作成功或失敗。所以建議使用參數化查詢。
插入操作
使用參數化查詢執(zhí)行插入操作,我們必須調用 SQLiteDatabase 類中內置的插入函數:
public
?long
?insert(String tableName,String nullColumnHack,ContentValues values)
insert()函數具有三個參數,tableName 是要插入數據表的名稱。nullColumnHack可能為空,SQL不允許在插入一個完全空的行時不指定至少一個列名。如果提供的值為空,則不知道列名,并且無法插入空行。如果未設置為null,則nullColumnHack參數提供可為null的列名的名稱,以便在值為空的情況下顯式插入null。values是包含一行數據的鍵值對。鍵應該是列名值是列值。如果插入成功,insert 函數將返回一個 long 值,即插入的行數,否則返回 – 1。
舉個栗子:
public
?void
?addItem(Item item) {
????
SQLiteDatabase db = getWritableDatabase();
????
ContentValues contentValues =?
new
?ContentValues();
????
contentValues.put(
"name"
, item.name);
????
contentValues.put(
"description"
, item.description);
????
db.insert(
"Items"
,?
null
, contentValues);
????
db.close();
}
更新操作
更新操作與插入操作非常相似,但它需要兩個額外的參數,它不需要 nullColumnHack。它共有四個參數,其中兩個類似于插入函數,即 tableName 和 contentValues。另外兩個是 whereClause(String) 和 whereArgs(String[]):
public
?int
?update(String tableName,ContentValues contentValues,String whereClause,String[] whereArgs)
這里 whereClause 是告訴數據庫在哪里更新表中的數據,建議在 whereClause 字符串中使用占位符 ? 表示將要傳遞的值。類似地,whereArgs 數組將包含那些傳遞給對應的占位符 ? 的值。如果成功,更新函數將返回受影響的行數,否則返回 0。
舉個栗子:
public
?void
?updateItem(Item item) {
????
SQLiteDatabase db = getWritableDatabase();
????
ContentValues contentValues =?
new
?ContentValues();
????
contentValues.put(
"id"
, item.id);
????
contentValues.put(
"name"
, item.name);
????
contentValues.put(
"description"
, item.description);
????
String whereClause =?
"id=?"
;
????
String whereArgs[] = {item.id.toString()};
????
db.update(
"Items"
, contentValues, whereClause, whereArgs);
}
刪除操作
與插入和更新類似,SQLiteDatabase 類中提供了刪除功能,因此刪除與更新功能非常相似,除了 ContentValues 對象,因為它在刪除中不需要。delete 函數有三個參數,它們與更新函數的參數完全相似,使用方式與更新函數相同。
舉個栗子:
public
?void
?deleteItem(Item item) {
????
SQLiteDatabase db = getWritableDatabase();
????
String whereClause =?
"id=?"
;
????
String whereArgs[] = {item.id.toString()};
????
db.delete(
"Items"
, whereClause, whereArgs);
}
這里 whereClause 是可選的,傳遞 null 將刪除表中的所有行。如果 whereClause 傳遞,刪除函數將返回受影響的行數,否則將返回 0。
注:如果要刪除所有行并要求返回刪除行的計數,則將 1 作為 whereClause 傳遞。
查詢操作
從數據庫表中讀取與插入、更新和刪除等其他函數有點不同。SQLiteDatabase 類提供query()方法來從表中讀取數據。query() 方法被不同的參數集重載。它返回Cursor對象,因此 Cursor 是一個帶有查詢數據的結果集,它提供了不同的功能,在讀取數據時非常有用。
以下是一些重載的查詢函數:
public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
查詢重載函數中的大多數參數都是可選的,除了 table 和不同的任何其他參數都可以作為 null 傳遞。如果 distinct 作為 true 傳遞,則游標數據集將沒有任何重復行。
??
public
?ArrayList<item> readAllItems() {
??????
ArrayList<item> items =?
new
?ArrayList<>();
??????
SQLiteDatabase db = getReadableDatabase();
??????
//see above point 2 function
??????
Cursor cursor = db.query(
"Items"
??????
,?
null
// columns - null will give all
??????
,?
null
// selection
??????
,?
null
// selection arguments
??????
,?
null
// groupBy
??????
,?
null
// having
??????
,?
null
// no need or order by for now;
??????
if
?(cursor !=?
null
) {
????????
while
?(cursor.moveToNext()) {
????????
// move the cursor to next row if there is any to read it's data
?????????????????
Item item = readItem(cursor);
?????????????????
items.add(item);
???????????
}
????????
}
??????
return
?items;
??
}
??
private
?Item readItem(Cursor cursor) {
??????
Item item =?
new
?Item();
??????
item.id = cursor.getInt(cursor.getColumnIndex(ItemTable.COL_ID));
??????
item.name = cursor.getString(cursor.getColumnIndex(ItemTable.COL_NAME));
??????
item.description = cursor.getString(cursor.getColumnIndex(ItemTable.COL_DESCRIPTION));
??????
return
?item;
??
}
</item></item>