【Android】數(shù)據(jù)存儲(三) 數(shù)據(jù)庫(SQLite)

SQLite
SQLite

前言

之前介紹過Android中保存數(shù)據(jù)的兩種方式:SharedPreferencesFile,這篇介紹另一種存儲數(shù)據(jù)的方式——數(shù)據(jù)庫。

數(shù)據(jù)庫:簡單來說可視為電子化的文件柜——存儲電子文件的處所,用戶可以對文件中的數(shù)據(jù)運行新增撩银、截取、更新、刪除等操作荷愕。

想必大家對數(shù)據(jù)庫都不陌生,想當(dāng)年上數(shù)據(jù)庫課的時候棍矛,被那些命令整得不要不要的安疗。

扯遠(yuǎn)了...

進(jìn)入正題,在Android開發(fā)的過程中够委,保存數(shù)據(jù)是難免的荐类。如果數(shù)據(jù)量較小的時候可用SharedPreferencesFile來保存,當(dāng)數(shù)據(jù)量較大且關(guān)系復(fù)雜的時候就要用到Android中的數(shù)據(jù)庫SQLite——輕量級數(shù)據(jù)庫系統(tǒng)茁帽。

用法

舉一個保存用戶信息的栗子:
創(chuàng)建一個數(shù)據(jù)庫mySQLite玉罐,在該數(shù)據(jù)庫中創(chuàng)建一個user表屈嗤,用來保存用戶信息,用戶屬性name(姓名:String類型)吊输、age(年齡:int類型)饶号。

創(chuàng)建一個用戶類(方便后面的操作)

/**
 * 用戶
 * Created by Gavin on 2016/5/30.
 */
public class User {
    /**
     * id
     */
    private int id;
    /**
     * 用戶名
     */
    private String name;
    /**
     * 年齡
     */
    private int age;
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

創(chuàng)建一個DatabaseHelper類

用來處理所有的數(shù)據(jù)庫操作。(這用到了SQL語句季蚂,不懂的看解釋)

/**
 * Created by Gavin on 2016/5/30.
 */
public class DatabaseHelper extends SQLiteOpenHelper {
    /**
     * 數(shù)據(jù)庫版本,需要升級數(shù)據(jù)庫時只要加一即可
     */
    private static final int DATABASE_VERSION = 1;
    /**
     * 數(shù)據(jù)庫名
     */
    private static final String DATABASE_NAME = "mySQLite.db";

    /**
     * 構(gòu)造方法
     * 每次創(chuàng)建DatabaseHelper對象時扭屁,若本應(yīng)用無該數(shù)據(jù)庫,則新建數(shù)據(jù)庫并調(diào)用onCreate方法然眼;
     * 若該數(shù)據(jù)庫已創(chuàng)建則直接使用已存在的數(shù)據(jù)庫且跳過onCreate方法
     * @param context   上下文
     */
    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    /**
     * 創(chuàng)建數(shù)據(jù)庫是時調(diào)用(只被調(diào)用一次)
     * @param db    數(shù)據(jù)庫
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        //創(chuàng)建user表,屬性:id(用戶id葵腹,主鍵)罪治、name(姓名)觉义、age(年齡)
        db.execSQL("CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(10),age INTEGER)");
    }

    /**
     * 跟新數(shù)據(jù)庫時調(diào)用
     * @param db            數(shù)據(jù)庫
     * @param oldVersion    舊版本號
     * @param newVersion    新版本號
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //升級:往user表,添加性別屬性
        //db.execSQL("ALTER TABLE user ADD COLUMN gender VARCHAR(2)");
    }
}

數(shù)據(jù)庫mySQLite在構(gòu)造方法中創(chuàng)建浴井,其中super()的參數(shù)有4個:
context:上下文晒骇;
datebaseName:數(shù)據(jù)庫名,一般以.db結(jié)尾洪囤;
factory : 當(dāng)打開的數(shù)據(jù)庫執(zhí)行查詢語句的時候 會創(chuàng)建一個Cursor對象, 這時會調(diào)用Cursor工廠類 factory, 可以填寫null默認(rèn)值撕氧;
version:數(shù)據(jù)庫版本伦泥,需要升級數(shù)據(jù)庫時將版本號加一,將升級的內(nèi)容寫在onUpgrade中即可不脯。

  • onCreate
    當(dāng)數(shù)據(jù)庫第一次創(chuàng)建的時候,會執(zhí)行onCreate()方法牺丙。這里的onCreate方法中創(chuàng)建了一張user表复局,db.execSQL()方法執(zhí)行了里面SQL語句。
  • onUpgrade
    數(shù)據(jù)庫升級時會調(diào)用onUpgrade()方法峦剔,這里的onUpgrade()方法往user表中添加了性別(gender)屬性。

操作數(shù)據(jù)庫

操作數(shù)據(jù)庫事秀,增刪查改是免不了的野舶。下面的方法都是在DatabaseHelper 中添加平道。

  • 增(Create)
    /**
     * 插入一條數(shù)據(jù)
     * @param user  用戶對象
     */
    public void insertAUser(User user) {
        //如果要對數(shù)據(jù)進(jìn)行更改,就調(diào)用此方法得到用于操作數(shù)據(jù)庫的實例,
        //該方法以讀和寫方式打開數(shù)據(jù)庫
        SQLiteDatabase database = getWritableDatabase();
        //向user表插入一條數(shù)據(jù)
        database.execSQL(
                "INSERT INTO user(name, age) VALUES(?,?)",
                new Object[]{user.getName(), user.getAge()});
    }

insertAUser()中使用了execSQL()執(zhí)行了插入數(shù)據(jù)的操作一屋。
這里用到的execSQL()有兩個參數(shù):
參數(shù)1:SQL指令冀墨,這里是一條插入命令涛贯,命令中的問號(?)為占位符
參數(shù)2:Object數(shù)組虫腋,數(shù)組中的內(nèi)容對應(yīng)參數(shù)1中的問號(稀余?)

  • 刪(Delete)
    /**
     * 根據(jù)id刪除一條數(shù)據(jù)
     * @param id    用戶id
     */
    public void deleteAUser(Integer id) {
        SQLiteDatabase database = getWritableDatabase();
        //根據(jù)id刪除一條數(shù)據(jù)
        database.execSQL("DELETE FROM user WHERE id=?",
                new Object[]{id});
    }

deleteAUser()根據(jù)用戶id睛琳,刪除了對應(yīng)的用戶信息。這里也是用了execSQL()執(zhí)行數(shù)據(jù)操作茁影。

  • 查(Read)
    /**
     * 讀取一條數(shù)據(jù)
     * @param id    用戶id
     * @return      用戶對象
     */
    public User readAUser(Integer id) {

        //如果只對數(shù)據(jù)進(jìn)行讀取丧凤,建議使用此方法
        SQLiteDatabase database = getReadableDatabase();
        Cursor cursor  = database.rawQuery(
                "SELECT * FROM user WHERE id=?",
                new String[]{id.toString()});
        if (cursor.moveToFirst()) {
            //讀取數(shù)據(jù),并返回
            User user = new User();
            user.setId(cursor.getInt(cursor.getColumnIndex("id")));
            user.setName(cursor.getString(cursor.getColumnIndex("name")));
            user.setAge(cursor.getInt(cursor.getColumnIndex("age")));
            cursor.close();
            return user;
        } else {
            //未讀出數(shù)據(jù)浩螺,返回空數(shù)據(jù)
            return null;
        }
    }

    /**
     * 獲取整個用戶列表
     * @return
     */
    public List<User> readAllUser() {
        SQLiteDatabase database = getReadableDatabase();
        Cursor cursor = database.rawQuery("SELECT * FROM user", new String[]{});
        List<User> list = new ArrayList<User>();
        //使用moveToNext()逐條讀取
        while (cursor.moveToNext()) {
            User user = new User();
            user.setId(cursor.getInt(cursor.getColumnIndex("id")));
            user.setName(cursor.getString(cursor.getColumnIndex("name")));
            user.setAge(cursor.getInt(cursor.getColumnIndex("age")));
            list.add(user);
        }
        cursor.close();
        return list;
    }

readAUser()中使用rawQuery方法獲取到用戶信息要出,通過cursor.moveToFirst()來獲取cursor的第一條數(shù)據(jù),接著通過cursor.getInt()或颊、cursor.getString()來獲取對應(yīng)的數(shù)據(jù)传于。

這里使用了getReadableDatabase()而不是getWritableDatabase()

  • 改(Update)
    /**
     * 更新一條用戶數(shù)據(jù)
     * @param user  用戶對象
     */
    public void updateAUser(User user) {
        SQLiteDatabase database = getWritableDatabase();
        //根據(jù)id更新一條數(shù)據(jù)
        database.execSQL(
                "UPDATE user SET name=?, age=? WHERE id=?",
                new Object[]{user.getName(), user.getAge(), user.getId()});
    }

這也沒什么好說的~~

execSQL()中用到的都最基礎(chǔ)的是SQL指令,至于復(fù)雜的自己去查吧

使用

輔助類DatabaseHelper寫完了通熄,接下來就是使用了

  • 插入一條數(shù)據(jù)
        DatabaseHelper helper = new DatabaseHelper(this);
        User user1 = new User();
        user1.setName("lisa");
        user1.setAge(20);
        helper.insertAUser(user1);//插入一條數(shù)據(jù)

        Log.i(TAG, helper.readAllUser().toString());//查看所有用戶

結(jié)果


結(jié)果
  • 根據(jù)id獲取一條數(shù)據(jù)唇辨,修改能耻,刪除。上面我們看到嗡贺,插入的那條數(shù)據(jù)id是1
        DatabaseHelper helper = new DatabaseHelper(this);
        User user1 = helper.readAUser(1);           //查找id為1的用戶
        Log.i(TAG, helper.readAUser(1).toString()); //顯示id為1的用戶
        user1.setAge(30);                           //將年齡改為30
        helper.updateAUser(user1);                  //更新數(shù)據(jù)庫
        Log.i(TAG, helper.readAUser(1).toString()); //顯示id為1的用戶
        helper.deleteAUser(user1.getId());          //刪除user1
        Log.i(TAG, helper.readAUser(1).toString()); //顯示id為1的用戶

結(jié)果


結(jié)果

上面的代碼中诫睬,分別打印了三次log帕涌。
第一次使用id為1的用戶蚓曼;
第二次是年齡被修改為30的用戶;
第三次是被刪除的用戶纫版,因為用戶不存在了,所以沒有第三條log
(由于helper.readAUser(1)沒有獲取到數(shù)據(jù)癞己,返回null痹雅,接著使用了toString()出現(xiàn)空指針異常,閃退了绩社,做了一個反面教材~~)愉耙。
不管怎么說,這次的目的達(dá)到了绘盟,增刪查改都o(jì)k了悯仙。

小結(jié)

使用SQLite就是在本地建了一個數(shù)據(jù)庫吠卷,使用數(shù)據(jù)庫中的表來保存數(shù)據(jù)祭隔。SQLite對數(shù)據(jù)的操作十分靈活,不過相比SharedPreferencesFile在使用上要復(fù)雜一些千贯,而且要一點的數(shù)據(jù)庫基礎(chǔ)搞坝。

附:DatabaseHelper完整代碼

package com.nostra13.universalimageloader.sample;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Gavin on 2016/5/30.
 */
public class DatabaseHelper extends SQLiteOpenHelper {
    /**
     * 數(shù)據(jù)庫版本,需要升級數(shù)據(jù)庫時只要加一即可
     */
    private static final int DATABASE_VERSION = 1;
    /**
     * 數(shù)據(jù)庫名
     */
    private static final String DATABASE_NAME = "mySQLite.db";

    /**
     * 構(gòu)造方法
     * 每次創(chuàng)建DatabaseHelper對象時敦第,若本應(yīng)用無該數(shù)據(jù)庫店量,則新建數(shù)據(jù)庫并調(diào)用onCreate方法融师;
     * 若該數(shù)據(jù)庫已創(chuàng)建則直接使用已存在的數(shù)據(jù)庫且跳過onCreate方法
     * factory : 當(dāng)打開的數(shù)據(jù)庫執(zhí)行查詢語句的時候 會創(chuàng)建一個Cursor對象, 這時會調(diào)用Cursor工廠類 factory, 可以填寫null默認(rèn)值
     * @param context   上下文
     */
    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    /**
     * 創(chuàng)建數(shù)據(jù)庫是時調(diào)用(只被調(diào)用一次)
     * @param db    數(shù)據(jù)庫
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        //創(chuàng)建user表,屬性:id(用戶id舀射,主鍵)、name(姓名)庙曙、age(年齡)
        db.execSQL("CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(10),age INTEGER)");
    }

    /**
     * 跟新數(shù)據(jù)庫時調(diào)用
     * @param db            數(shù)據(jù)庫
     * @param oldVersion    舊版本號
     * @param newVersion    新版本號
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //升級user表捌朴,添加性別
        //db.execSQL("ALTER TABLE user ADD COLUMN gender VARCHAR(2)");
    }

    /**
     * 插入一條數(shù)據(jù)
     * @param user  用戶對象
     */
    public void insertAUser(User user) {
        //如果要對數(shù)據(jù)進(jìn)行更改张抄,就調(diào)用此方法得到用于操作數(shù)據(jù)庫的實例,該方法以讀和寫方式打開數(shù)據(jù)庫
        SQLiteDatabase database = getWritableDatabase();
        //向user表插入一條數(shù)據(jù)
        database.execSQL(
                "INSERT INTO user(name, age) VALUES(?,?)",
                new Object[]{user.getName(), user.getAge()});
    }

    /**
     * 更新一條用戶數(shù)據(jù)
     * @param user  用戶對象
     */
    public void updateAUser(User user) {
        SQLiteDatabase database = getWritableDatabase();
        //根據(jù)id更新一條數(shù)據(jù)
        database.execSQL(
                "UPDATE user SET name=?, age=? WHERE id=?",
                new Object[]{user.getName(), user.getAge(), user.getId()});
    }

    /**
     * 根據(jù)id刪除一條數(shù)據(jù)
     * @param id    用戶id
     */
    public void deleteAUser(Integer id) {
        SQLiteDatabase database = getWritableDatabase();
        //根據(jù)id刪除一條數(shù)據(jù)
        database.execSQL("DELETE FROM user WHERE id=?",
                new Object[]{id});
    }

    /**
     * 獲取整個用戶列表
     * @return
     */
    public List<User> readAllUser() {
        SQLiteDatabase database = getReadableDatabase();
        Cursor cursor = database.rawQuery("SELECT * FROM user", new String[]{});
        List<User> list = new ArrayList<User>();
        while (cursor.moveToNext()) {
            User user = new User();
            user.setId(cursor.getInt(cursor.getColumnIndex("id")));
            user.setName(cursor.getString(cursor.getColumnIndex("name")));
            user.setAge(cursor.getInt(cursor.getColumnIndex("age")));
            list.add(user);
        }
        cursor.close();
        return list;
    }

    /**
     * 讀取一條數(shù)據(jù)
     * @param id    用戶id
     * @return      用戶對象
     */
    public User readAUser(Integer id) {

        //如果只對數(shù)據(jù)進(jìn)行讀取署惯,建議使用此方法
        SQLiteDatabase database = getReadableDatabase();
        Cursor cursor  = database.rawQuery(
                "SELECT * FROM user WHERE id=?",
                new String[]{id.toString()});
        if (cursor.moveToFirst()) {
            //讀取數(shù)據(jù)极谊,并返回
            User user = new User();
            user.setId(cursor.getInt(cursor.getColumnIndex("id")));
            user.setName(cursor.getString(cursor.getColumnIndex("name")));
            user.setAge(cursor.getInt(cursor.getColumnIndex("age")));
            cursor.close();
            return user;
        } else {
            //未讀出數(shù)據(jù),返回空數(shù)據(jù)
            return null;
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帆吻,一起剝皮案震驚了整個濱河市猜煮,隨后出現(xiàn)的幾起案子败许,更是在濱河造成了極大的恐慌,老刑警劉巖愕撰,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件被丧,死亡現(xiàn)場離奇詭異甥桂,居然都是意外死亡,警方通過查閱死者的電腦和手機黄选,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來律歼,“玉大人啡专,你說我怎么就攤上這事∨峡觯” “怎么了慧库?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵齐板,是天一觀的道長。 經(jīng)常有香客問我橡羞,道長宽档,這世上最難降的妖魔是什么庵朝? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任九府,我火速辦了婚禮,結(jié)果婚禮上肺蔚,老公的妹妹穿的比我還像新娘儡羔。我一直安慰自己,他們只是感情好仇冯,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布族操。 她就那樣靜靜地躺著,像睡著了一般泼舱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尺迂,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天枪狂,我揣著相機與錄音宋渔,去河邊找鬼。 笑死严蓖,一個胖子當(dāng)著我的面吹牛氧急,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播毒姨,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼弧呐,長吁一口氣:“原來是場噩夢啊……” “哼嵌纲!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鸠蚪,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤师溅,失蹤者是張志新(化名)和其女友劉穎墓臭,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體起便,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年铸史,在試婚紗的時候發(fā)現(xiàn)自己被綠了琳轿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耿芹。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖琉闪,靈堂內(nèi)的尸體忽然破棺而出砸彬,到底是詐尸還是另有隱情,我是刑警寧澤蛀蜜,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布滴某,位于F島的核電站滋迈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏椰憋。R本人自食惡果不足惜赔退,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一证舟、第九天 我趴在偏房一處隱蔽的房頂上張望女责。 院中可真熱鬧,春花似錦抵知、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽初茶。三九已至恼布,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間倔幼,已是汗流浹背堕伪。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工欠雌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留禁炒,地道東北人悠瞬。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓凌外,卻偏偏與公主長得像轿亮,于是被迫代替她去往敵國和親劳秋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容