1. 程式人生 > >Android程式設計學習筆記 之 SQLite資料儲存

Android程式設計學習筆記 之 SQLite資料儲存

SQLite是一個輕量級的嵌入式的資料庫,我們在Android開發中不需要安裝任何外掛即可使用,

如果是root過的手機,可以在data/data/包名/databases裡面找到db資料庫檔案,推薦用SQLiteSpysqlite3進行檢視

支援高達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常用的方法

  1. void onCreate(SQLiteDatabase db):建立資料庫時呼叫,建庫建表的操作
  2. void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):版本更新時呼叫,自動執行
  3. SQLiteDatabase getReadableDatabase()
    :建立或開啟一個只讀資料庫,只能查詢,不能寫入,不能更新,並返回一個SQLiteDatabase物件
  4. 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語句的小知識,有興趣可以點選超連結檢視

  1. 主鍵前要加下劃線
  2. _id必須要int最好Integer
  3. primary key宣告為主鍵(允許有多個主鍵)
  4. autoincrement自增
  5. not null不允許為空
原生的SQL建表語句如下:
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()方法,有興趣的可以查閱API
SQLiteDatabase 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語句,有興趣可以點選上方的超連結。

SQLiteDatabase的常用方法
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中的資料

在進行增刪查改操作之前,我們先要認識下兩個類ContentValuesCursor,這兩個我們可以理解為就是儲存了一行的資料,前者存放,後者讀取

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語句對一個程式設計師是很重要的基本功。