1. 程式人生 > >SQLite基本用法

SQLite基本用法

  在Android中一共提供了5種資料儲存方式,分別為:

  (1)Files:通過FileInputStream和FileOutputStream對檔案進行操作。具體使用方法可以參閱博文《Android學習筆記34:使用檔案儲存資料》。

  (2)Shared Preferences:常用來儲存鍵值對形式的資料,對系統配置資訊進行儲存。具體使用方法可以參閱博文《Android學習筆記35:使用Shared Preferences方式儲存資料》。

  (3)Content Providers:資料共享,用於應用程式之間資料的訪問。

  (4)SQLite:Android自帶的輕量級關係型資料庫,支援SQL語言,用來儲存大量的資料,並且能夠對資料進行使用、更新、維護等操作。

  (5)Network:通過網路來儲存和獲取資料。

  本篇博文介紹第四種方式,通過Android自帶的SQLite資料庫儲存資料。

1.SQLite簡介

  SQLite是一款開源的、嵌入式關係型資料庫,第一個版本Alpha釋出於2000年。SQLite在便攜性、易用性、緊湊性、高效性和可靠性方面有著突出的表現。

  SQLite和C/S模式的資料庫軟體不同,它是一款嵌入式資料庫,沒有獨立執行的程序,與所服務的應用程式在應用程式程序空間內共生共存。它的程式碼與應用程式程式碼也是在一起的,或者說嵌入其中,作為託管它的程式的一部分。因此不存在資料庫的客戶端和伺服器,使用SQLite一般只需要帶上它的一個動態庫,就可以享受它的全部功能。

  資料庫伺服器在程式中的好處是不需要網路配置或管理。將資料庫客戶端與伺服器執行在同一個程序中,可以省去不少的操作及麻煩:不用擔心防火牆或者地址解析;不用浪費時間管理複雜的授權和許可權;可以減少網路呼叫相關的消耗;可以簡化資料庫管理並使程式更容易部署。

  SQLite資料庫通過資料庫級上的獨佔性和共享鎖來實現獨立事務處理。這意味著多個程序可以在同一時間從同一資料庫讀取資料,但是隻有一個可以寫入資料。在某個程序向資料庫執行寫操作之前,必須獲得獨佔鎖定。在發出獨佔鎖定後,其他的讀寫操作將不會再發生。

  此外,SQLite資料庫中的所有資訊(比如表、檢視、觸發器等)都包含在一個檔案內,方便管理和維護。SQLite資料庫還支援大部分作業系統,除電腦上使用的作業系統之外,很多手機上使用的作業系統同樣可以執行。同時,SQLite資料庫還提供了多語言的程式設計介面,供開發者使用。

2.SQL基本命令

  SQL是與關係型資料庫通訊的唯一方式。它專注於資訊處理,是為構建、讀取、寫入、排序、過濾、對映、分組、聚集和通常的管理資訊而設計的宣告式語言。

  在講解SQL基本命令之前,有必要先了解一下SQLite所支援的資料型別都有哪些。

2.1 SQLite支援的資料型別

  SQLite採用動態資料儲存型別,會根據存入的值自動進行判斷。SQLite支援以下5種資料型別:

  (1)NULL:空值

  (2)INTEGER:帶符號的整型

  (3)REAL:浮點型

  (4)TEXT:字串文字

  (5)BLOB:二進位制物件

2.2 SQL基本命令

  表是探索SQLite中SQL的起點,也是關係型資料庫中資訊的標準單位,所有的操作都是以表為中心的。那麼如何使用SQL命令建立一張表呢?

2.2.1建立表

  表是由行和列組成的,列稱為欄位,行稱為記錄。

  使用CREATE命令可以建立表,CREATE命令的一般格式為:

  CREATE [TEMP/TEMPORARY] TABLE table_name (column_definitions [, constraints]);

  其中,[]中的內容是可選的,用TEMP或TEMPORARY關鍵字宣告的表是臨時表,這種表只存活於當前會話,一旦連線斷開,就會被自動銷燬。如果沒有明確指出建立的表是臨時表,則建立的是基本表,將會在資料庫中持久存在,這也是資料庫中最常見的表。

  CREATE TABLE命令至少需要一個表名和一個欄位名,上述命令中的table_name表示表名,表名必須與其他識別符號不同。column_definitions由用逗號分隔的欄位列表組成,每個欄位定義包括一個名稱、一個域(型別)和一個逗號分隔的欄位約束。其中,域是指儲存在該列的資訊的型別,約束用來控制什麼樣的值可以儲存在表中或特定的欄位中。

  一條建立表的命令示例如下:

1   CREATE TABLE tab_student (studentId INTEGER PRIMARY KEY AUTOINCREMENT, 
2                             studentName VARCHAR(20), 
3                             studentAge INTEGER);

  如上,我們建立了一個名為tab_student的表,該表包含3個欄位:studentId、 studentName和studentAge,其資料型別分別為:INTEGER、VARCHAR和INTEGER。

  此外,通過使用關鍵字PRIMARY KEY,我們指定了欄位studentId所在的列是主鍵。主鍵確保了每一行記錄在某種方式上與表中的其他行記錄是不同的(唯一的),進而確保了表中的所有欄位都是可定址的。

  SQLite為主鍵提供自增長功能,當定義欄位型別為INTEGER PRIMARY KEY時,SQLite將為該欄位建立預設值,該預設值確保整數值是唯一的。SQLite使用64-bit單符號整數主鍵,因此,該欄位的最大值是9,223,372,036,854,775,807。當達到最大值時,SQLite會自動搜尋該欄位還未使用的值,並作為要插入的值。從表中刪除記錄時,rowid可能被回收並在後面的插入中使用。因此,新建立的rowid不一定是按照嚴格順序增長的。如果想要SQLite使用唯一的自動主鍵值,而不是填補空白,可以在主鍵定義INTEGER PRIMARY KEY中加入關鍵字AUTOINCREMENT。AUTOINCREMENT關鍵字阻止rowid回收,它將為新插入的記錄產生新的(不是回收的)rowid。

2.2.2插入記錄

  使用INSERT命令可以一次插入一條記錄,INSERT命令的一般格式為:

  INSERT INTO tab_name (column_list) VALUES (value_list);

  其中,tab_name指明將資料插入到哪個表中,column_list是用逗號分隔的欄位名稱,這些欄位必須是表中存在的,value_list是用逗號分隔的值列表,這些值是與column_list中的欄位一一對應的。

  比如,向剛才建立的tab_student表中插入一條記錄,便可以使用如下的語句完成:


  INSERT
INTO tab_student (studentId, studentName, studentAge) VALUES (1, “jack”, 23);

  通過以上的語句,便插入了一條studentName=”jack”, studentAge=”23”的記錄,該記錄的主鍵為studentId=1。

2.2.3更新記錄

  使用UPDATE命令可以更新表中的記錄,該命令可以修改一個表中一行或者多行中的一個或多個欄位。UPDATE命令的一般格式為:

  UPDATE tab_name SET update_list WHERE predicate;

  其中,update_list是一個或多個欄位賦值的列表,欄位賦值的格式為column_name=value。WHERE子句使用斷言識別要修改的行,然後將更新列應用到這些行。

  比如,要更新剛才插入到tab_student表中的記錄,便可以使用如下的語句完成:


  UPDATE
tab_student SET studentName=”tom”, studentAge=25WHERE studentId=1;

  通過以上的語句,便可以將剛才插入的主鍵為studentId=1的記錄更新為studentName=”tom”, studentAge=”25”了。

2.2.4刪除記錄

  使用DELETE命令可以刪除表中的記錄,DELETE命令的一般格式為:

  DELETE FROM table_name WHERE predicate;

  其中,table_name指明所要刪除的記錄位於哪個表中。和UPDATE命令一樣,WHERE子句使用斷言識別要刪除的行。

  比如,要刪除剛才插入的記錄,便可以使用如下的語句完成:

  
  DELETE FROM tab_student WHERE studentId=1;

2.2.5查詢記錄

  SELECT命令是查詢資料庫的唯一命令。SELECT命令也是SQL命令中最大、最複雜的命令。

  SELECT命令的通用形式如下:

  SELECT [distinct] heading 

  FROM tables 

  WHERE predicate 

  GROUP BY columns 

  HAVING predicate 

  ORDER BY columns 

  LIMIT count,offset;

  其中,每個關鍵字(如FROM、WHERE、HAVING等)都是一個單獨的子句,每個子句由關鍵字和跟隨的引數構成。GROUP BY和HAVING一起工作可以對GROUP BY進行約束。ORDER BY使記錄集在返回之前按一個或多個欄位的值進行排序,可以指定排序方式為ASC(預設的升序)或DESC(降序)。此外,還可以使用LIMIT限定結果集的大小和範圍,count指定返回記錄的最大數量,offset指定偏移的記錄數。

  在上述的SELECT命令通用形式中,除了SELECT之外,所有的子句都是可選的。目前最常用的SELECT命令由三個子句組成:SELECT、FROM、WHERE,其基本語法形式如下:

  SELECT heading FROM tables WHERE predicate;

  比如,要查詢剛才插入的記錄,便可以使用如下的語句完成:

  
  SELECT
studentId, studentName, studentAge FROM tab_student WHERE studentId=1;

  至此,我們介紹了SQL中最基本和最常用的CREATE、INSERT、UPDATE、DELETE和SELECT命令。當然了,這裡只是對其進行了簡單的介紹,有關SQLite中SQL命令的詳細使用方法,可以參閱《SQLite權威指南》一書的第三章和第四章。

3.資料庫操作輔助類SQLiteOpenHelper

  Android提供了一個重要的類SQLiteOpenHelper,用於輔助使用者對SQLite資料庫進行操作。

  SQLiteOpenHelper的建構函式原型如下:

  public SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version);

  其中,引數context表示應用程式執行的環境,包含應用程式所需的共享資源。引數name表示Android的資料庫名字。引數factory是SQLiteDatabase.CursorFactory類物件,用於儲存查詢Android SQLite資料庫的結果集。引數version表示應用程式所用的資料庫的版本,該版本並非SQLite的真正版本,而是指定應用程式中的SQLite資料庫的版本,當該版本號發生變化時,將會觸發SQLiteOpenHelper類中的onUpgrade()或onDowngrade()方法。

  SQLiteOpenHelper類的所有方法如圖1所示。

圖1 SQLiteOpenHelper類的方法

  其中,close()方法用於關閉SQLiteOpenHelper物件中的SQLite資料庫;getReadableDatabase()方法和getWriteableDatabase()方法類似,getReadableDatabase()方法以只讀狀態開啟SQLiteOpenHelper物件中指定的SQLite資料庫,任何想要修改資料庫的操作都是不允許的;getWriteableDatabase()方法也是開啟資料庫,但是允許資料庫正常的讀/寫操作;在一個不存在的資料庫上呼叫任何方法時,都會隱式的呼叫SQLiteOpenHelper物件的onCreate()方法;當應用程式第一次訪問資料庫時,則會呼叫onOpen()方法,但是,如果版本號發生了變化的話,則會呼叫onUpgrade()或onDowngrade()方法。

4.資料庫類SQLiteDatabase

  SQLiteDatabase類用來完成對資料庫的操作任務,比如表的選擇、插入、更新和刪除語句等。

  SQLiteDatabase類中常用的用於執行SQL語句的方法有以下一些。

  (1)execSQL()方法:

  public void execSQL (String sql);

  public void execSQL (String sql, Object[] bindArgs);

  (2)query()方法:

  public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String  groupBy, String  having,String orderBy, String limit);

  public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal);

  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);

  (3)queryWithFactory()方法:

  public Cursor queryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[]columns, String selection, String[] selectionArgs, String groupBy, String having, String  orderBy, String  limit,CancellationSignal cancellationSignal);

  public Cursor queryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[]columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);

  (4)rawQuery()方法:

  public Cursor rawQuery (String sql, String[] selectionArgs, CancellationSignal cancellationSignal);

  public Cursor rawQuery (String sql, String[] selectionArgs);

  (5)rawQueryWithFactory()方法:

  public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, String sql, String[]  selectionArgs,String editTable);

  public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, String sql, String[]  selectionArgs,String editTable, CancellationSignal cancellationSignal);

  其中,execSQL()方法都有一個引數sql,這個引數是一個SQL語句。第二個引數bindArgs接收一個數組,陣列中的每個成員捆綁了一個查詢。execSQL()方法用於執行那些沒有返回值的查詢語句,比如建立、插入、更新和修改表。

  query()方法和queryWithFactory()方法是在資料庫中執行一些輕量級的單查詢語句,引數包括table、columns、groupBy、having、orderBy、limit等SQL語句關鍵字。這些方法允許將SQL語句傳遞給相關方法,而不必直接使用SQL語句。

  rawQuery()方法和rawQueryWithFactory()方法也都有一個引數sql,用於執行SQL查詢語句,返回值是Cursor物件。這兩個方法都有一個版本能夠接收一個字串陣列selectionArgs作為引數,通過這個引數,SQLiteDatabase物件將把捆綁的SQL語句中的問號(?)用這個陣列中的值代替,並按照一一對應的位置關係進行取代。

  SQLiteDatabase類提供了大約50個方法,除此之外還有一些用於開啟資料庫的方法(如openDatabase()、openOrCreateDatabase()等),用於管理SQLite事務的方法(如beginTransaction()、endTransaction()等),用於測試資料庫是否被鎖住的方法(如isDbLockedByCurrentThread()、isDbLockedByOtherThread()等),以及獲取資料庫基本資訊的方法(如getMaximumSiza()、getVersion()等)。這裡就不一一介紹了,具體可以參閱SQLiteDatabase類的API幫助文件

5.遊標類Cursor

  在Android中,查詢資料是通過Cursor類來實現的,當我們使用SQLiteDatabase.query()或SQLiteDatabase.rawQuery()方法時,會得到一個Cursor物件,Cursor指向的就是每一條記錄,它提供了很多有關查詢的方法,如圖2所示。

圖2 Cursor類的常用方法

6.封裝介面

  有了以上的基礎,我們便可以按照MVC的架構,封裝一個介面層,在該介面層中實現對SQLite資料庫的具體操作。

  以下分別以新增資料、更新資料、查詢資料為例講解其具體的實現方法。在實現這些方法之前,我們首先需要建立一張表。這裡我建立了一個名為MySQLiteOpenHelper的類,讓它繼承自SQLiteOpenHelper類,並實現了SQLiteOpenHelper類的onCreate()方法,在該方法裡實現建立一張表的操作,具體原始碼如下:

複製程式碼
1     /*
2      * Function  :    建立表
3      * Author    :    部落格園-依舊淡然
4      */
5     public void onCreate(SQLiteDatabase db) {
6         db.execSQL("CREATE TABLE tab_student (studentId INTEGER PRIMARY KEY AUTOINCREMENT, " + 
"studentName VARCHER(20), " +
"studentAge INTEGER)"); 7 }
複製程式碼

  通過以上的程式碼,我們建立了一張名為“tab_student”的表,並在該表中建立了三個欄位,分別為:studentId、studentName和studentAge。並且指定了studentId欄位作為該表的主鍵。

6.1新增資料

  新增資料可以使用SQLiteDatabase.execSQL(String sql, Object[] bindArgs)方法來實現,具體如下:

複製程式碼
1     /*
2      * Function  :    新增資料
3      * Author    :    部落格園-依舊淡然
4      */
5     public void addStudentInfo(Student student) {
6         db = mySQLiteOpenHelper.getWritableDatabase();
7         db.execSQL("INSERT INTO tab_student (studentId, studentName, studentAge) values (?, ?, ?)", 
8           new Object[] {student.getStudentId(), student.getStudentName(), student.getStudentAge()});
9     }
複製程式碼

  其中,通過第二個引數bindArgs,使SQL語句中的問號(?)與這個陣列中的值形成一一對應關係,從而將值寫入到“tab_student”表中的對應欄位中。

6.2更新資料

  更新資料的方法與新增資料的方法大致相同,具體如下:

複製程式碼
1    /*
2     * Function  :    更新資料
3     * Author    :    部落格園-依舊淡然
4     */
5    public void updateStudentInfo(Student student) {
6        db = mySQLiteOpenHelper.getWritableDatabase();
7        db.execSQL("UPDATE tab_student SET studentName = ?, studentAge = ? WHERE studentId = ?", 
          new Object[] {student.getStudentName(), student.getStudentAge(), student.getStudentId()});
8    }
複製程式碼

6.3查詢資料

  查詢資料時,因為需要返回查詢的結果,所以需要使用SQLiteDatabase.rawQuery()方法將查詢的結果返回,具體如下:

複製程式碼
 1     /*
 2      * Function  :    查詢資料
 3      * Author    :    部落格園-依舊淡然
 4      */
 5     public Student findStudentInfo(int id) {
 6         db = mySQLiteOpenHelper.getWritableDatabase();
 7         String sql = "SELECT studentId, studentName, studentAge FROM tab_student WHERE studentId = ?";
 8         Cursor cursor = db.rawQuery(sql, new String[] {String.valueOf(id)});
 9         if(cursor.moveToNext()) {
10             return new Student(cursor.getInt(cursor.getColumnIndex("studentId")),     
cursor.getString(cursor.getColumnIndex("studentName")), 11 cursor.getInt(cursor.getColumnIndex("studentAge"))); 12 } 13 return null; 14 }
複製程式碼

  可以看出,通過使用SQLiteDatabase.rawQuery()方法可以將查詢到的結果存入Cursor物件中。然後,我們可以使用Cursor物件的getXXX()方法將查詢結果從Cursor物件中取出來。

  當然了,我們還可以根據實際的需要,去實現更多的介面方法,比如,刪除資料、獲取資料列表、獲取資料個數等等。

  封裝好了以上的這些介面方法,便可以很方便的在程式中直接呼叫這些方法,不必再去關心底層資料庫的呼叫,而將精力放在UI介面的設計實現上。