Android數(shù)據(jù)存儲之SQLite數(shù)據(jù)庫存儲

本文目錄:

1. 創(chuàng)建數(shù)據(jù)庫

2. 升級數(shù)據(jù)庫

3. 添加數(shù)據(jù)

4. 更新數(shù)據(jù)

5. 刪除數(shù)據(jù)

6. 查詢數(shù)據(jù)


分割線


(本文原理內(nèi)容來自《Android第一行代碼(第二版)》)

介紹:
SQLite是一款輕量級的關系型數(shù)據(jù)庫短纵,它的運算速度非城玻快伪冰,占用源很少脚作,通常只需要幾百KB的內(nèi)存就足夠了,因而特別適合在移動設備上使用役听。
SQLite不僅支持標準的SQL語法羔砾,還遵循數(shù)據(jù)庫的ACID事務躏救,所以只要你以前使用過其他的關系型數(shù)據(jù)庫,就可以很快地上手 SQLite肌访。
SQLite比一般的數(shù)據(jù)庫要簡單得多找默,它甚至不用設置用戶名和密碼就可以使用。
Android正是把這個功能極為強大的數(shù)據(jù)庫嵌入到了系統(tǒng)當中吼驶,使得本地持久化的功能有了一次質(zhì)的飛躍惩激。

1. 創(chuàng)建數(shù)據(jù)庫

Android提供了一個SQLiteOpenHelper幫助類,用于對數(shù)據(jù)庫進行創(chuàng)建和升級
SQLiteOpenHelper是一個抽象類蟹演,使用時需要創(chuàng)建自己的類去繼承它咧欣。
SQLiteOpenHelper有兩個抽象方法onCreate()onUpgrade(),必須在自己的類中重寫這兩個方法轨帜,然后分別在這兩個方法中實現(xiàn)創(chuàng)建升級數(shù)據(jù)庫的邏輯魄咕。

SQLiteOpenHelper中還有兩個非常重要的實例方法: getReadableDatabase()getWritableDatabase()
這兩個方法都可以創(chuàng)建或打開一個現(xiàn)有的數(shù)據(jù)庫(如果數(shù)據(jù)庫已存在則直接打開蚌父,否則創(chuàng)建一個新的數(shù)據(jù)庫)哮兰,并返回一個可對數(shù)據(jù)庫進行讀寫操作的對象。
不同的是苟弛,當數(shù)據(jù)庫不可寫入的時候(如磁盤空間已滿)喝滞,
getReadableDatabase()方法返回的對象將以只讀的方式去打開數(shù)據(jù)庫
getWritableDatabase()方法則將出現(xiàn)異常

SQLiteOpenHelper中有兩個構造方法可供重寫,一般使用參數(shù)少的那個構造方法即可膏秫。
這個構造方法中接收4個參數(shù):
第一個參數(shù)是 Context右遭,必須要有它才能對數(shù)據(jù)庫進行操作。
第二個參數(shù)是數(shù)據(jù)庫名缤削,創(chuàng)建數(shù)據(jù)庫時使用的就是這里指定的名稱窘哈。
第三個參數(shù)允許我們在查詢數(shù)據(jù)的時候返回一個自定義的 Cursor,一般都是傳入 null亭敢。
第四個參數(shù)表示當前數(shù)據(jù)庫的版本號滚婉,可用于對數(shù)據(jù)庫進行升級操作。

構建出SQLiteOpenHelper的實例之后帅刀,再調(diào)用它的 getReadableDatabase()getWritableDatabase()方法就能夠創(chuàng)建數(shù)據(jù)庫了让腹,數(shù)據(jù)庫文件會存放在/data/data/<package name>/databases/日錄下远剩。此時重寫的 onCreate()方法也會得到執(zhí)行,所以通常會在這里去處理一些創(chuàng)建表的邏輯骇窍。

Demo:

我們希望創(chuàng)建一個名為BookStore的數(shù)據(jù)庫瓜晤,并在這個庫中創(chuàng)建一張Book表,表中有id腹纳、作者痢掠、價格、頁數(shù)和書名只估。
(SQLite中integer代表整型,real表示浮點型着绷,text表示文本類型蛔钙,blob表示二進制類型)

  • 新建MyDatabaseHelper類繼承自SQLiteOpenHelper
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)";

    private Context mContext;

    public MyDatabaseHelper(Context context, String name,SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

這里將建表語句定義為字符串常量,并在onCreate()方法中調(diào)用了execSQL()方法執(zhí)行建表語句荠医。

  • activity_main.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/create_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create database"/>

</LinearLayout>

布局里只加入了一個按鈕吁脱,用于創(chuàng)建數(shù)據(jù)庫

  • MainActivity代碼
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);

        //創(chuàng)建數(shù)據(jù)
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();
            }
        });

    }
}

這里我們在onCreate()方法中構建了一個MyDatabaseHelper對象,并且通過構造函數(shù)的參數(shù)將數(shù)據(jù)庫名指定為BookStore.db彬向,版本號指定為1兼贡,然后在Create database按鈕的點擊事件里調(diào)用了getWritableDatabase()方法。這樣當?shù)谝淮吸c擊Create database按鈕時娃胆,就會檢測到當前程序中并沒有BookStore.db這個數(shù)據(jù)庫遍希,于是會創(chuàng)建該數(shù)據(jù)庫并調(diào)用MyDatabaseHelper中的onCreate()方法,這樣Book表也就得到了創(chuàng)建里烦,然后會彈出一個Toast提示創(chuàng)建成功凿蒜。再次點擊Create database按鈕時,會發(fā)現(xiàn)此時已經(jīng)存在BookStore.db數(shù)據(jù)庫了胁黑,因此不會再創(chuàng)建一次

create database.gif

此時BookStore.db數(shù)據(jù)庫和Book表已經(jīng)創(chuàng)建成功了废封,因為當你再次點擊Create database按鈕時,不會有Toast彈出丧蘸。

2. 升級數(shù)據(jù)庫

現(xiàn)在已經(jīng)有了一個Book表用于存放書的各種詳細數(shù)據(jù)漂洋,如果想再添加一張Category表用于記錄圖書的分類,怎么辦呢力喷?

  • 在MyDatabaseHelper中添加語句:
圖片.png

此時運行程序刽漂,Category表并沒有創(chuàng)建成功,因為之前我們的BookStore.db數(shù)據(jù)庫已經(jīng)存在了弟孟,不管怎樣點擊Create database按鈕爽冕,MyDatabaseHelper中的onCreate()方法都不會執(zhí)行,也就無法創(chuàng)建新表了披蕉。

解決這個問題就要用到升級數(shù)據(jù)庫功能

  • 在MyDatabaseHelper的onUpgrade()函數(shù)中加入以下語句
圖片.png
 @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }
  • 現(xiàn)在我們需要讓onUpgrade()方法得到執(zhí)行颈畸,修改SQLiteOpenHelper構造方法的第四個參數(shù)乌奇,之前設置的1,現(xiàn)在傳入一個大于1的值眯娱,表示我們對數(shù)據(jù)庫進行升級了礁苗。
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);

        //創(chuàng)建數(shù)據(jù)
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();
            }
        });

    }
}

重新運行程序,Category表就創(chuàng)建成功了徙缴。

3. 添加數(shù)據(jù)

SQLiteDatabase中提供了一個insert()方法试伙,用于添加數(shù)據(jù)。
它接受3個參數(shù)
第一個參數(shù):表名
第二個參數(shù):用于在未指定添加數(shù)據(jù)的情況下給某些可為空的列自動賦值NULL于样,我們一般直接傳入null
第三個參數(shù):一個ContentValues對象疏叨,它提供了一系列put()方法重載,用于向ContentValues中添加數(shù)據(jù)穿剖,只需將表中的每個列名以及對應的數(shù)據(jù)傳入即可蚤蔓。

Demo:

  • activity_main.xml中加入Add data按鈕控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/create_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create database"/>

    <Button
        android:id="@+id/add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add data"/>

</LinearLayout>
  • 更改MainActivity代碼,onCreate()中加入代碼
public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);

        //創(chuàng)建數(shù)據(jù)
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();
            }
        });
        
        //添加數(shù)據(jù)
       Button addData = (Button) findViewById(R.id.add_data);
       addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                // 開始組裝第一條數(shù)據(jù)
                values.put("name", "The Da Vinci Code");
                values.put("author", "Dan Brown");
                values.put("pages", 454);
                values.put("price", 16.96);
                db.insert("Book", null, values); // 插入第一條數(shù)據(jù)
                values.clear();
                // 開始組裝第二條數(shù)據(jù)
                values.put("name", "The Lost Symbol");
                values.put("author", "Dan Brown");
                values.put("pages", 510);
                values.put("price", 19.95);
                db.insert("Book", null, values); // 插入第二條數(shù)據(jù)
            }
        });
    }
}

在添加數(shù)據(jù)按鈕的點擊事件里面糊余,我們先獲取到了SQLiteDatabase對象秀又,然后使用ContentValues來對要添加的數(shù)據(jù)進行組裝。

這里只對Book表里其中四列的數(shù)據(jù)進行了組裝贬芥,id那一列沒并沒給它賦值吐辙。這是因為在前面創(chuàng)建表的時候,我們就將id列設置為自增長了蘸劈,它的值會在入庫的時候自動生成昏苏,所以不需要手動給它賦值了。

接下來調(diào)用了insert()方法將數(shù)據(jù)添加到表當中威沫,注意這里我們實際上添加了兩條數(shù)據(jù)捷雕,上述代碼中使用 Contentvalues分別組裝了兩次不同的內(nèi)容,并調(diào)用了兩次 insert()方法壹甥。

重新運行程序救巷,點擊ADD DATA 按鈕便可在表中添加數(shù)據(jù)了

4. 更新數(shù)據(jù)

關于更新數(shù)據(jù),SQLiteDatabase中提供了一個update()方法句柠,用于對數(shù)據(jù)更新浦译。
該方法接受4個參數(shù)
第一個參數(shù):表名
第二個參數(shù):Contentvalues對象,在這里把要更新的數(shù)據(jù)組裝進去
第三個參數(shù)第四個參數(shù):用于約束更新某一行或某幾行的數(shù)據(jù)(默認更新所有行)

Demo:

  • activity_main.xml中加入update data按鈕控件
    <Button
        android:id="@+id/update_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Update data"/>
  • 更改MainActivity代碼溯职,onCreate()中加入代碼
        //更新數(shù)據(jù)
        Button updateData = (Button) findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price", 10.99);
                db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" });
            }
        });

這里在更新數(shù)據(jù)按鈕的點擊事件里面構建了一個 ContentValues對象精盅,并且只給它指定了一組數(shù)據(jù),說明我們只是想把價格這一列的數(shù)據(jù)更新成10.99谜酒。然后調(diào)用了SQLiteDatabase的update()方法去執(zhí)行具體的更新操作叹俏,可以看到,這里使用了第三僻族、第四個參數(shù)來指定具體更新哪幾行粘驰。第三個參數(shù)對應的是SQL語句的 where部分屡谐,表示更新所有name等于?的行,而?是一個占位符蝌数,可以通過第四個參數(shù)提供的一個字符串數(shù)組為第三個參數(shù)中的每個占位符指定相應的內(nèi)容愕掏。因此上述代碼想表達的意圖是將名字是 The Da Vinci Code的這本書的價格改成10.99。

5. 刪除數(shù)據(jù)

SQLiteDatabase中提供了一個delete()方法顶伞,用于刪除數(shù)據(jù)饵撑。
該方法接受3個參數(shù)
第一個參數(shù):表名
第二個參數(shù)第三個參數(shù):用于約束刪除某一行或某幾行的數(shù)據(jù)(默認刪除所有行)

Demo:

  • activity_main.xml中加入delete data按鈕控件
     <Button
        android:id="@+id/delete_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Delete data" />
  • 更改MainActivity代碼,onCreate()中加入代碼
        //刪除數(shù)據(jù)
        Button deleteButton = (Button) findViewById(R.id.delete_data);
        deleteButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.delete("Book", "pages > ?", new String[] { "500" });
            }
        });

程序指定刪除那些頁數(shù)超過500頁的書

6. 查詢數(shù)據(jù)

SQLiteDatabase中提供了一個query()方法唆貌,用于對數(shù)據(jù)進行查詢滑潘。
該方法參數(shù)比較復雜,最短的一個重載方法也需要7個參數(shù)
第一個參數(shù):表名
第二個參數(shù):指定查詢的列名(默認所有列)
第三個參數(shù):和第四個參數(shù):用于約束查詢某一行或某幾行的數(shù)據(jù)(默認查詢所有行)
第五個參數(shù):指定需要group by的列锨咙,不指定則不進行group by操作
第六個參數(shù):對group by之后的數(shù)據(jù)進一步過濾
第七個參數(shù):指定查詢結果的排序方式

Demo:

  • activity_main.xml中加入query data按鈕控件
    <Button
        android:id="@+id/query_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Query data" />
  • 更改MainActivity代碼语卤,onCreate()中加入代碼
        //查詢數(shù)據(jù)
        Button queryButton = (Button) findViewById(R.id.query_data);
        queryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                // 查詢Book表中所有的數(shù)據(jù)
                Cursor cursor = db.query("Book", null, null, null, null, null, null);
                if (cursor.moveToFirst()) {
                    do {
                        // 遍歷Cursor對象,取出數(shù)據(jù)并打印
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        String author = cursor.getString(cursor.getColumnIndex("author"));
                        int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                        double price = cursor.getDouble(cursor.getColumnIndex("price"));
                        Log.d("MainActivity", "book name is " + name);
                        Log.d("MainActivity", "book author is " + author);
                        Log.d("MainActivity", "book pages is " + pages);
                        Log.d("MainActivity", "book price is " + price);
                    } while (cursor.moveToNext());
                }
                cursor.close();
            }
        });

我們首先在查詢按鈕的點擊事件里面調(diào)用了SQLiteDatabase的query()方法查詢數(shù)據(jù)蓖租。這里的query()方法非常簡單粱侣,只是使用了第一個參數(shù)指明去查詢Book表羊壹,后面的參數(shù)全部為null蓖宦,表示希望查詢這張表中的所有數(shù)據(jù)。雖然這張表中目前只剩下一條數(shù)據(jù)了油猫。査詢完之后就得到了一個Cursor對象稠茂,接著我們調(diào)用它的 moveToFirst()方法將數(shù)據(jù)的指針移動到第一行的位置,然后進入了一個循環(huán)當中情妖,去遍歷查詢到的每一行數(shù)據(jù)睬关。在這個循環(huán)中可以通過Cursor的getColumnIndex()方法獲取到某一列在表中對應的位置索引,然后將這個索引傳入到相應的取值方法中毡证,就可以得到從數(shù)據(jù)庫中讀取到的數(shù)據(jù)了电爹。接著我們使用Log將數(shù)據(jù)打印出來。最后別忘了調(diào)用close()方法關閉Cursor料睛。

重新運行程序丐箩,可以看到logcat打印的內(nèi)容如下:

圖片.png
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恤煞,隨后出現(xiàn)的幾起案子屎勘,更是在濱河造成了極大的恐慌,老刑警劉巖居扒,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件概漱,死亡現(xiàn)場離奇詭異,居然都是意外死亡喜喂,警方通過查閱死者的電腦和手機瓤摧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門竿裂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人姻灶,你說我怎么就攤上這事铛绰。” “怎么了产喉?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵捂掰,是天一觀的道長。 經(jīng)常有香客問我曾沈,道長这嚣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任塞俱,我火速辦了婚禮姐帚,結果婚禮上,老公的妹妹穿的比我還像新娘障涯。我一直安慰自己罐旗,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布唯蝶。 她就那樣靜靜地躺著九秀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪粘我。 梳的紋絲不亂的頭發(fā)上鼓蜒,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音征字,去河邊找鬼都弹。 笑死,一個胖子當著我的面吹牛匙姜,可吹牛的內(nèi)容都是我干的畅厢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼氮昧,長吁一口氣:“原來是場噩夢啊……” “哼框杜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起郭计,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤霸琴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后昭伸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梧乘,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了选调。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夹供。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖仁堪,靈堂內(nèi)的尸體忽然破棺而出哮洽,到底是詐尸還是另有隱情,我是刑警寧澤弦聂,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布鸟辅,位于F島的核電站,受9級特大地震影響莺葫,放射性物質(zhì)發(fā)生泄漏匪凉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一捺檬、第九天 我趴在偏房一處隱蔽的房頂上張望再层。 院中可真熱鬧,春花似錦堡纬、人聲如沸聂受。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛋济。三九已至,卻和暖如春职车,著一層夾襖步出監(jiān)牢的瞬間瘫俊,已是汗流浹背鹊杖。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工悴灵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骂蓖。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓积瞒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親登下。 傳聞我的和親對象是個殘疾皇子茫孔,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344