如果有JDBC的經驗,那麼在這裡會容易的多。Android中操作數據庫首先要通過一個 類:android.database.sqlite.SQLiteOpenHelper。它封裝了如何打開一個數據庫,其中當然也包含如果數據庫不存在 就創建這樣的邏輯。看一個例子: pubilc class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "com.roiding.simple.note"; private static final int DATABASE_VERSION = 1; private static final String NOTES_TABLE_NAME = "notes"; DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + NOTES_TABLE_NAME + " (id integer primary key autoincrement, name text);"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS notes"); onCreate(db); } } 這裡面,如下的語句需要解釋: super(context, DATABASE_NAME, null, DATABASE_VERSION) 數據庫連接的初始化,中間的那個null,是一個CursorFactory參數,沒有仔細研究這個參數,暫時置空吧。 public void onCreate(SQLiteDatabase db) 這裡面的onCreate是指數據庫onCreate時,而不是DatabaseHelper的onCreate。也就是說,如果已經指定 database已經存在,那麼在重新運行程序的時候,就不會執行這個方法了。要不然,豈不是每次重新啟動程序都要重新創建一次數據庫了!在這個方法中,完成了數據庫的創建工作。也就是那個execSQL()方法。 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 在程序的開發維護過程中,數據庫的結構可能會有變化,那麼這個方法就有用處了。在DatabaseHelper這個對象一創建時,就已經把參數 DATABASE_VERSION傳入,這樣,如果Android發現此版本與現有版本不一致,就會調用這個onUpgrate方法。於是,可以在這裡面實現一些數據的upgrade工作,比如說創建一個臨時表,將數據由臨時表中轉到新的表結構中。需要注意的是,這裡面的onUpgrade是在版本不一致時調用,也就是說不管當前需要的版本高於現有版本還是低於現有版本,都會出發這個方法,類似的這種情況,就需要對oldVersion和 newVersion進行判斷之後再決定使用什麼策略來更新數據。 在Android中,數據庫存放在 /data/data/PACKAGE_NAME/databases 目錄下。 接下來就可以使用這個Helper來操作數據庫了,操作數據庫也就無非是增、刪、改、查。先看一個增的例子: public static void insert(Context context, String s) { DatabaseHelper mOpenHelper = new DatabaseHelper(context); String table = "notes"; String nullColumnHack = "id"; ContentValues values = new ContentValues(); values.put("name", "www.roiding.com"); long id = mOpenHelper.getReadableDatabase().insert(table, nullColumnHack, values); mOpenHelper.getReadableDatabase().close(); } DatabaseHelper mOpenHelper = new DatabaseHelper(context); 如果和JDBC例子的話,這一步貌似就像是獲得了一個Statement,用它就可以操作數據庫了。 ContentValues values = new ContentValues(); Android在向數據庫中插入數據的時候,要求數據存放到ContentValues中,這裡面的ContentValues其實就是一個 Map,Key值是字段名稱,Value值是字段的值。這樣,也許你會發現一個問題,那數據類型怎麼辦?其實在SQLite數據庫中就是沒有數據類型的, 一切都是字符串。 mOpenHelper.getReadableDatabase().insert(table,nullColumnHack, values); 將數據入庫,注意這裡面有一個nullColumnHack,看文檔是和所有字段都是空的記錄有關係,我沒有去實驗他具體的效果,只是隨便給他一個字段名稱。 再看一個查的例子: public static void select(Context context) { DatabaseHelper mOpenHelper = new DatabaseHelper(context); String table = "notes"; String[] columns = new String[] { "id", "name" }; String selection = "id>? and name<>?"; String[] selectionArgs = new String[] { "0", "roiding.com" }; String groupBy = null; String having = null; String orderBy = "id desc"; String limit = "1"; Cursor c = mOpenHelper.getReadableDatabase().query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit); c.moveToFirst(); for (int i = 0; i < c.getCount(); i++) { String s = c.getString(1); c.moveToNext(); } c.close(); mOpenHelper.getReadableDatabase().close(); } DatabaseHelper mOpenHelper = new DatabaseHelper(context); 於前文中的相同 mOpenHelper.getReadableDatabase().query(); 通過mOpenHelper.getReadableDatabase(),會得到一個SQLiteDatabase類型的只讀的數據庫連接,在這裡直接調用了他的query方法。這個query方法相對複雜,因為他將一個完整的SQL語句拆成了若幹個部分: table:表名。相當於SQL的from後面的部分。那如果是多表聯合查詢怎麼辦?那就用逗號將兩個表名分開,拼成一個字符串作為table的值。 columns:要查詢出來的列名。相當於SQL的select後面的部分。 selection:查詢條件,相當於SQL的where後面的部分,在這個語句中允許使用「?」,也就是說這個用法和JDBC中的 PreparedStatement的用法相似。 selectionArgs:對應於selection的值,selection有幾個問號,這裡就得用幾個值。兩者必須一致,否則就會有異常。 groupBy:相當於SQL的group by後面的部分 having:相當於SQL的having後面的部分 orderBy:相當於SQL的order by後面的部分,如果是倒序,或者是聯合排序,可以寫成類似這樣:String orderBy = 「id desc, name」; limit:指定結果集的大小,它和Mysql的limit用法不太一樣,mysql可以指定從多少行開始之後取多少條,例如「limit 100,10」,但是這裡只支持一個數值。 c.moveToFirst(); 這一句也比較重要,如果讀取數據之前,沒有這一句,會有異常。 c.getString(1); 與JDBC一致了,Android不支持按字段名來取值,只能用序號。 再看一個刪除和修改的例子: public static void delete(Context context) { DatabaseHelper mOpenHelper = new DatabaseHelper(context); String table = "notes"; String selection = "id>? and name<>?"; String[] selectionArgs = new String[] { "0", "roiding.com" }; String whereClause = selection; String[] whereArgs = selectionArgs; mOpenHelper.getWritableDatabase().delete(table, whereClause, whereArgs); mOpenHelper.getWritableDatabase().close(); } 有了上面的基礎這裡就容易理解了,這裡的whereClause相當於前面的selection,whereArgs相當於前面的 selectionArgs。 public static void update(Context context) { DatabaseHelper mOpenHelper = new DatabaseHelper(context); String table = "notes"; String selection = "id>? and name<>?"; String[] selectionArgs = new String[] { "0", "roiding.com" }; String whereClause = selection; String[] whereArgs = selectionArgs; ContentValues values = new ContentValues(); values.put("name", "www.roiding.com"); mOpenHelper.getWritableDatabase().update(table, values, whereClause, whereArgs); mOpenHelper.getWritableDatabase().close(); } 這個update的用法,綜合select和delete就可以理解。 注意: Cursor和Databases要及時關閉,不然也會有異常。 getWritableDatabase()和getReadableDatabase()在當前的Android版本中貌似可以通用,像上面的 insert,用的就是getReadableDatabase。 在真實的應用中,會對上面這些基本操作做更高一級的抽象和封裝,使之更容易使用。在select時,除了用上述的方法,將分段的SQL語句傳進去之外,Android還支持一種方法:使用SQLiteQueryBuilder。如果使用的是上述的分段SQL語句的方法,在Android的內部實現中,也是先將分段的SQL使用SQLiteQueryBuilder的靜態方法來生成一個真正的SQL的,而且,我沒有看出來使用 SQLiteQueryBuilder的優勢 http://charles-android.blogspot.tw/2010/03/androiddatabases.html |