Android入門(十二)SQLite事務、升級資料庫

來源:互聯網
上載者:User

標籤:

原文連結:http://www.orlion.ga/610/

一、事務

    SQLite支援事務,看一下Android如何使用事務:比如 Book表中的資料都已經很老了,現在準備全部廢棄掉替換成新資料,可以先使用delete()方法將Book表中的資料刪除, 然後再使用insert()方法將新的資料添加到表中。我們要保證的是,刪除舊資料和添加新資料的操作必須一起完成,否則就還要繼續保留原來的舊資料。

                Button replaceData = (Button) findViewById(R.id.replace_data);replaceData.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {SQLiteDatabase db = dbHelper.getWritableDatabase();db.beginTransaction();db.delete("book", null, null);try {if (true) {// 手動拋出異常,讓事務失敗throw new Exception();}ContentValues values = new ContentValues();values.put("name", "book new");values.put("author", "orlion");values.put("pages", 200);values.put("price", 100);db.insert("book", null, values);db.setTransactionSuccessful(); // 事務已經執行成功} catch (Exception e) {e.printStackTrace();} finally {db.endTransaction(); // 結束事務}}});

    上述代碼就是Android中事務的標準用法, 首先調用SQLiteDatabase的beginTransaction()方法來開啟一個事務,然後在一個異常捕獲的代碼塊中去執行具體的資料庫操作,當所有的操作都完成之後,調用 setTransactionSuccessful()表示事務已經執行成功了,最後在 finally代碼塊中調用 endTransaction()來結束事務。注意觀察,我們在刪除舊資料的操作完成後手動拋出了一個 NullPointerException,這樣添加新資料的代碼就執行不到了。不過由於事務的存在,中途出現異常會導致事務的失敗,此時舊資料應該是刪除不掉的。

 

二、升級資料庫的最佳寫法

    // 這裡直接複製《第一行代碼原文》

    Android入門(十)SQLite建立升級資料庫 一文中升級資料庫的方式是非常粗暴的,為了保證資料庫中的表是最新的,我們只是簡單地在 onUpgrade()方法中刪除掉了當前所有的表,然後強制重新執行了一遍 onCreate()方法。這種方式在產品的開發階段確實可以用,但是當產品真正上線了之後就絕對不行了。

    每一個資料庫版本都會對應一個版本號碼, 當指定的資料庫版本號碼大於當前資料庫版本號碼的時候, 就會進入到 onUpgrade()

方法中去執行更新操作。這裡需要為每一個版本號碼賦予它各自改變的內容,然後在onUpgrade()方法中對當前資料庫的版本號碼進行判斷,再執行相應的改變就可以了。

    接著就讓我們來類比一個資料庫升級的案例,還是由 MyDatabaseHelper類來對資料庫進行管理。第一版的程式要求非常簡單,只需要建立一張 Book表,MyDatabaseHelper中的代碼如下所示:

    

public class MyDatabaseHelper extends SQLiteOpenHelper {    public static final String CREATE_BOOK = "create table Book ("        + "id integer primary key autoincrement, "        + "author text, "        + "price real, "        + "pages integer, "        + "name text)";    public MyDatabaseHelper(Context context, String name, CursorFactory        factory, int version) {        super(context, name, factory, version);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL(CREATE_BOOK);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

    不過,幾星期之後又有了新需求,這次需要向資料庫中再添加一張 Category表。於是,修改 MyDatabaseHelper中的代碼,如下所示:

public class MyDatabaseHelper extends SQLiteOpenHelper {    public static final String CREATE_BOOK = "create table Book ("        + "id integer primary key autoincrement, "        + "author text, "        + "price real, "        + "pages integer, "        + "name text)";    public static final String CREATE_CATEGORY = "create table Category ("        + "id integer primary key autoincrement, "        + "category_name text, "        + "category_code integer)";    public MyDatabaseHelper(Context context, String name,        CursorFactory factory, int version) {        super(context, name, factory, version);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL(CREATE_BOOK);        db.execSQL(CREATE_CATEGORY);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        switch (oldVersion) {        case 1:            db.execSQL(CREATE_CATEGORY);            default:        }    }}

    可以看到,在 onCreate()方法裡我們新增了一條建表語句,然後又在 onUpgrade()方法中添加了一個 switch判斷,如果使用者當前資料庫的版本號碼是 1,就只會建立一張 Category表。這樣當使用者是直接安裝的第二版的程式時,就會將兩張表一起建立。而當使用者是使用第二版的程式覆蓋安裝第一版的程式時,就會進入到升級資料庫的操作中,此時由於 Book表已經存在了,因此只需要建立一張 Category表即可。但是沒過多久,新的需求又來了,這次要給 Book表和 Category表之間建立關聯,需要在 Book表中添加一個 category_id的欄位。 再次修改 MyDatabaseHelper中的代碼, 如下所示:

public class MyDatabaseHelper extends SQLiteOpenHelper {    public static final String CREATE_BOOK = "create table Book ("        + "id integer primary key autoincrement, "        + "author text, "        + "price real, "        + "pages integer, "        + "name text, "        + "category_id integer)";    public static final String CREATE_CATEGORY = "create table Category ("        + "id integer primary key autoincrement, "        + "category_name text, "        + "category_code integer)";    public MyDatabaseHelper(Context context, String name,        CursorFactory factory, int version) {        super(context, name, factory, version);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL(CREATE_BOOK);        db.execSQL(CREATE_CATEGORY);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        switch (oldVersion) {        case 1:            db.execSQL(CREATE_CATEGORY);        case 2:            db.execSQL("alter table Book add column category_id integer");        default:        }    }}

    可以看到,首先我們在 Book表的建表語句中添加了一個 category_id列,這樣當使用者直接安裝第三版的程式時,這個新增的列就已經自動添加成功了。然而,如果使用者之前已經安裝了某一版本的程式,現在需要覆蓋安裝,就會進入到升級資料庫的操作中。在 onUpgrade()方法裡,我們添加了一個新的 case,如果當前資料庫的版本號碼是 2,就會執行 alter命令來為Book表新增一個 category_id列。

    這裡請注意一個非常重要的細節,switch中每一個 case的最後都是沒有使用 break的,為什麼要這麼做呢?這是為了保證在跨版本升級的時候, 每一次的資料庫修改都能被全部執行到。比如使用者當前是從第二版程式升級到第三版程式的,那麼 case 2中的邏輯就會執行。而如果使用者是直接從第一版程式升級到第三版程式的,那麼 case 1和 case 2中的邏輯都會執行。使用這種方式來維護資料庫的升級,不管版本怎樣更新,都可以保證資料庫的表結構是最新的,而且表中的資料也完全不會丟失了。

Android入門(十二)SQLite事務、升級資料庫

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.