Android程式設計學習筆記 之 SQLite資料儲存
SQLite是一個輕量級的嵌入式的資料庫,我們在Android開發中不需要安裝任何外掛即可使用,
如果是root過的手機,可以在data/data/包名/databases裡面找到db資料庫檔案,推薦用SQLiteSpy或sqlite3進行檢視
支援高達2TB大小的資料庫,以單個檔案形式存在,以B-樹的資料結構形式儲存。
在安全性方面,允許多個程序同時讀,只允許一個程序進行寫。(以上概念可以無視
SQLite支援的資料型別和我們程式設計時用的資料型別有所不同。
支援null(空值),integer(整型),real(浮點型),text(字串),blob(二進位制型),
雖然還支援動態資料型別,自動檢測值的型別,進行強制轉換,但是還是推薦嚴格的使用上述資料型別。
我們先來認識一下這兩個類SQLiteDatabase和SQLiteOpenHelper,有個大致印象。
SQLiteDatabase:管理SQLite,進行增、刪、查、改操作。
SQLiteOpenHelper:是SQLiteDatabase的幫助類,用於管理資料庫的建立和版本更新。
我們在Android開發中使用SQLite進行資料儲存大致的步驟如下:
①建立或開啟SQLite資料庫,建立或開啟一個表Table
②進行增、刪、查、改操作
③關閉資料庫手動釋放記憶體
①建立或開啟SQLite資料庫,建立或開啟一個表Table
每個程式都有自己的資料庫,互不干擾。如果要訪問其他應用程式的資料庫的話,博主還沒研究到,這裡待補充
一般的Android開發中建庫建表都是由SQLiteOpenHelper進行封裝的實現的,好處就是,我們在Activity中進行建表建庫操作時不用關心具體的實現
我們需要寫一個類繼承它,重寫其中的onCreat()和onUpgrade()方法,下面簡單介紹下SQLiteOpenHelper常用的方法
- void onCreate(SQLiteDatabase db):建立資料庫時呼叫,建庫建表的操作
- void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):版本更新時呼叫,自動執行
- SQLiteDatabase getReadableDatabase()
- SQLiteDatabase getWritableDatabase():建立或開啟一個讀寫資料庫,並返回一個SQLiteDatabase物件
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
public MySQLiteOpenHelper(Context context, String name) {
super(context, name, null, 1);//自定義建構函式,建立名為name的資料庫
}
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);//context表示上下文,name表示資料庫的名字,version表示資料庫的版本號
//factory可選的資料庫遊標工廠類,當查詢(query)被提交時,該物件會被呼叫來例項化一個遊標。預設為null。
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {//建立資料庫時呼叫,建庫建表的操作
sqLiteDatabase.execSQL("create table if not exists Student(" + //如果不存在Student表,則建表
"_id integer primary key autoincrement," + //以自增的integer型別的_id為主鍵
"name text not null" + //新增不允許為null的名為name的text型別的一列
"age integer not null)"); //新增不允許為null的名為age的integer型別的一列
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
//資料庫版本更新時呼叫,自動執行,不用手動呼叫,比如增加了一列資料
}
}
這裡還有些SQL語句的小知識,有興趣可以點選超連結檢視
- 主鍵前要加下劃線
- _id必須要int最好Integer
- primary key宣告為主鍵(允許有多個主鍵)
- autoincrement自增
- not null不允許為空
create table if not exists 表名(主鍵名 資料型別 primary key autoincrement,資料名 資料型別 not null)
create table if not exists table(_id integer primary key autoincrement, name text not null, age integer not null)
寫好這個SQLiteOpenHelper類後,我們在Activity中例項化這個SQLiteOpenHelper,並傳入上下文context和資料庫的名字mydb。
就可以用getReadableDatabase()或者getWritableDatabase()獲得一個SQLiteDatabase物件,自此,建庫建表完成。
MySQLiteOpenHelper mySQLiteOpenHelper = new MySQLiteOpenHelper(this, "mydb");
SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
實際上,這樣的建庫建表還是不夠底層的,在super裡面建庫建表呼叫了openOrCreateDatabase()方法,有興趣的可以查閱APISQLiteDatabase db = openOrCreateDatabase(String name, int mode, CursorFactory factory));//開啟本應用程式的資料庫
//name建議加上db的字尾,在其他裝置(電腦)開啟,表示資料庫的名字
//mode在之前有SharedPrefen講過,有私有,只讀,
//factory可選的資料庫遊標工廠類,當查詢(query)被提交時,該物件會被呼叫來例項化一個遊標。預設為null。
附:博主以前寫記事本App的時候,在Activity中使用瞭如下語句進行建立資料庫(不建議使用)
是通過絕對路徑來新建一個數據庫,
第一個引數是絕對路徑,第二個引數是CursorFactory是一個用於返回的Cursor工廠,如果為null,則使用預設的工廠。
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(this.getFilesDir().toString() + "/note.db3", null);//可以開啟其他程式的資料庫?
②進行增、刪、查、改操作
進行SQL資料庫增、刪、查、改操作分為兩種方式:
一種是使用execSQL輸入原生的SQL語句,效率低難查錯,不能錯一個字母一個空格,要求嚴格輸入,開發時不推薦使用,寫Demo時可以熟悉練手
一種是用Android自帶的簡化版的封裝好的方法進行增刪查改。
我們這裡就不詳細介紹原生的SQL語句,有興趣可以點選上方的超連結。
void execSQL(String sql) | 執行原生的SQL語句 |
long insert(String table, String nullColumnHack, ContentValues values) | 在table表中,插入values的一行資料,如果values有null,則用nullColumnHack填充null值所在的列名,返回插入的是第幾行 |
int delete(String table, String whereClause, String[] whereArgs) | 在table表中,刪除滿足whereArgs資料的whereClause條件,返回刪除的是第幾行 |
int update(String table, ContentValues values, String whereClause, String[] whereArgs) | 在table表中,更新滿足whereArgs資料的whereClause條件,用values進行修改更新的一行資料,返回更新的是第幾行 |
Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) | |
Cursor rawQuery(String sql, String[] selectionArgs) | 使用原生的sql語句查詢,將String型別的sql中的?替換為selectionArgs中的資料 |
在進行增刪查改操作之前,我們先要認識下兩個類ContentValues和Cursor,這兩個我們可以理解為就是儲存了一行的資料,前者存放,後者讀取
ContentValues用來儲存一組可以被ContentResolver處理的值,類似Map,採用鍵值對的方式儲存key-value
Cursor翻譯為遊標,是Android查詢資料後得到的一個管理資料集合的類,類似於List集合,推薦手動釋放記憶體,避免記憶體溢位。
增:
其實就是插入。
原生的SQL語句是類似鍵值對的方式存入的。
insert into 表名(資料名...) values(資料的值...)
insert into table(name, age) values('小明', 18)
在Android的方法中,我們需要用到ContentValues來儲存一行的資料,和Map<String key, Object value>很像contentValues.put("key", value);//鍵值對儲存
db.insert(String table, String nullColumnHack, ContentValues contentValues)//返回插入到第幾行,返回新添記錄的行號,與主鍵id無關
db.insert(表名, 當contentValues為null時該列的名稱, 一行的資料)
一般情況下,只要contentValues不為null,nullColumnHack都不起作用,所以nullColumnHack設定為null即可。
並且nullColumnHack的列名不能是主鍵列的列名,也不能是非空列的列名
當這一行新增完畢,記得將contentValues清空,或者重新new一個物件
contentValues.clear();//新增新資料的時候要記得清空,這是一行的資料
改:
也就是更新,update,同樣需要contentValues來進行儲存資料,這裡就給個用法。
同樣,每次更新完都要將contentValues清空,或者重新new一個物件
int update(String table, ContentValues values, String whereClause, String[] whereArgs)
int update(表名, 一行的資料, 限制條件, 限制條件的值)
int update("table", values, "_id>?", new String[]{"3"});//更新所有_id>3的資料為contentValues
刪:
顧名思義,就是刪除,不需要藉助ContentValues和Cursor
int delete(String table, String whereClause, String[] whereArgs )
int delete(表名, 限制條件, 限制條件的值)
int delete("table", "name like ?", new String[]{"%明%"});//%是萬用字元,刪除所以名字中帶有"明"的人
查:
查詢,這裡需要用到Cursor遊標,Cursor類似於List<Map<String key, Object value>>,可以看成是符合搜尋條件的行組成的一個子表的指標
Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs,
String groupBy, String having, String orderBy, String limit)
Cursor query(是否去重, 表名, 返回的列名, 查詢條件, 查詢條件的值, 控制分組, 控制過濾, 控制排序, 控制查詢的資料數)
Cursor query(true, "table", null為返回所有列, "_id>?", new String[]{"0"}, null, null, "name", null);//查詢所有_id>0的資料,並按name升序排序
Cursor rawQuery(String sql, String[] selectionArgs)
query和rawQuery的區別在於:
query是Android自己封裝的API,不容易出錯
rawQuery是直接使用SQL語句進行查詢的,也就是第一個引數字串,在字串內的“?”會被後面的String[]陣列逐一對換掉。
他們都返回一個Cursor,可以看成是符合搜尋條件的行組成的一個子表的指標,預設指向第一行,Cursor有一些方法
int getCount();//返回總記錄條數
boolean isFirst();//當前遊標是否指向第一條記錄,成功則返回true,失敗返回false
boolean isLast();//當前遊標是否指向最後一條記錄
boolean moveToFirst();//當前遊標移動到第一條記錄,預設在第一行
boolean moveToLast();//當前遊標移動到最後一條記錄
boolean move(int position);//當前遊標移動到第position條記錄
boolean moveToNext();//當前遊標移動到下一條記錄
boolean moveToPrevious();//當前遊標移動到上一條記錄
int getColumnIndexOrThrow(String columnName);//根據columnName列名獲取第幾列的資料,返回第幾列
int getInt(int columnIndex);//獲得指定列索引的值,轉成int型
String getString(int columnIndex);//獲得指定列索引的值,轉成String型,還有其他就不一一列舉
在查詢完畢後,我們需要手動關閉Cursor
//Cursor預設在第一行,
if(cursor!=null){
while(cursor.moveToNext()){//移向下一行
Log.i("info", "_id:"+cursor.getInt(cursor.getColumnIndex("_id")));//獲取名為_id的列的,在這一行的int值
Log.i("info", "name:"+cursor.getString(cursor.getColumnIndex("name")));
Log.i("info", "age:"+cursor.getInt(cursor.getColumnIndex("age")));
}
cursor.close();//關閉Cursor
}
db.close();
③關閉資料庫手動釋放記憶體
最後關閉資料庫
db.close();
最後,雖然SQL原生語句寫起來可能會很容易出錯,但是還是要去學習,SQL語句對一個程式設計師是很重要的基本功。