【Android】数据存储(三) 数据库(SQLite)

SQLite
SQLite

前言

之前介绍过Android中保存数据的两种方式:SharedPreferencesFile,这篇介绍另一种存储数据的方式——数据库。

数据库:简单来说可视为电子化的文件柜——存储电子文件的处所,用户可以对文件中的数据运行新增、截取、更新、删除等操作

想必大家对数据库都不陌生,想当年上数据库课的时候,被那些命令整得不要不要的。

扯远了...

进入正题,在Android开发的过程中,保存数据是难免的。如果数据量较小的时候可用SharedPreferencesFile来保存,当数据量较大且关系复杂的时候就要用到Android中的数据库SQLite——轻量级数据库系统。

用法

举一个保存用户信息的栗子:
创建一个数据库mySQLite,在该数据库中创建一个user表,用来保存用户信息,用户属性name(姓名:String类型)、age(年龄:int类型)。

创建一个用户类(方便后面的操作)

/**
 * 用户
 * 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;
    }
}

创建一个DatabaseHelper类

用来处理所有的数据库操作。(这用到了SQL语句,不懂的看解释)

/**
 * Created by Gavin on 2016/5/30.
 */
public class DatabaseHelper extends SQLiteOpenHelper {
    /**
     * 数据库版本,需要升级数据库时只要加一即可
     */
    private static final int DATABASE_VERSION = 1;
    /**
     * 数据库名
     */
    private static final String DATABASE_NAME = "mySQLite.db";

    /**
     * 构造方法
     * 每次创建DatabaseHelper对象时,若本应用无该数据库,则新建数据库并调用onCreate方法;
     * 若该数据库已创建则直接使用已存在的数据库且跳过onCreate方法
     * @param context   上下文
     */
    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    /**
     * 创建数据库是时调用(只被调用一次)
     * @param db    数据库
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建user表,属性:id(用户id,主键)、name(姓名)、age(年龄)
        db.execSQL("CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(10),age INTEGER)");
    }

    /**
     * 跟新数据库时调用
     * @param db            数据库
     * @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)");
    }
}

数据库mySQLite在构造方法中创建,其中super()的参数有4个:
context:上下文;
datebaseName:数据库名,一般以.db结尾;
factory : 当打开的数据库执行查询语句的时候 会创建一个Cursor对象, 这时会调用Cursor工厂类 factory, 可以填写null默认值;
version:数据库版本,需要升级数据库时将版本号加一,将升级的内容写在onUpgrade中即可。

  • onCreate
    当数据库第一次创建的时候,会执行onCreate()方法。这里的onCreate方法中创建了一张user表,db.execSQL()方法执行了里面SQL语句。
  • onUpgrade
    数据库升级时会调用onUpgrade()方法,这里的onUpgrade()方法往user表中添加了性别(gender)属性。

操作数据库

操作数据库,增删查改是免不了的。下面的方法都是在DatabaseHelper 中添加。

  • 增(Create)
    /**
     * 插入一条数据
     * @param user  用户对象
     */
    public void insertAUser(User user) {
        //如果要对数据进行更改,就调用此方法得到用于操作数据库的实例,
        //该方法以读和写方式打开数据库
        SQLiteDatabase database = getWritableDatabase();
        //向user表插入一条数据
        database.execSQL(
                "INSERT INTO user(name, age) VALUES(?,?)",
                new Object[]{user.getName(), user.getAge()});
    }

insertAUser()中使用了execSQL()执行了插入数据的操作。
这里用到的execSQL()有两个参数:
参数1:SQL指令,这里是一条插入命令,命令中的问号(?)为占位符
参数2:Object数组,数组中的内容对应参数1中的问号(?)

  • 删(Delete)
    /**
     * 根据id删除一条数据
     * @param id    用户id
     */
    public void deleteAUser(Integer id) {
        SQLiteDatabase database = getWritableDatabase();
        //根据id删除一条数据
        database.execSQL("DELETE FROM user WHERE id=?",
                new Object[]{id});
    }

deleteAUser()根据用户id,删除了对应的用户信息。这里也是用了execSQL()执行数据操作。

  • 查(Read)
    /**
     * 读取一条数据
     * @param id    用户id
     * @return      用户对象
     */
    public User readAUser(Integer id) {

        //如果只对数据进行读取,建议使用此方法
        SQLiteDatabase database = getReadableDatabase();
        Cursor cursor  = database.rawQuery(
                "SELECT * FROM user WHERE id=?",
                new String[]{id.toString()});
        if (cursor.moveToFirst()) {
            //读取数据,并返回
            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 {
            //未读出数据,返回空数据
            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的第一条数据,接着通过cursor.getInt()、cursor.getString()来获取对应的数据。

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

  • 改(Update)
    /**
     * 更新一条用户数据
     * @param user  用户对象
     */
    public void updateAUser(User user) {
        SQLiteDatabase database = getWritableDatabase();
        //根据id更新一条数据
        database.execSQL(
                "UPDATE user SET name=?, age=? WHERE id=?",
                new Object[]{user.getName(), user.getAge(), user.getId()});
    }

这也没什么好说的~~

execSQL()中用到的都最基础的是SQL指令,至于复杂的自己去查吧

使用

辅助类DatabaseHelper写完了,接下来就是使用了

  • 插入一条数据
        DatabaseHelper helper = new DatabaseHelper(this);
        User user1 = new User();
        user1.setName("lisa");
        user1.setAge(20);
        helper.insertAUser(user1);//插入一条数据

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

结果


结果
  • 根据id获取一条数据,修改,删除。上面我们看到,插入的那条数据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);                  //更新数据库
        Log.i(TAG, helper.readAUser(1).toString()); //显示id为1的用户
        helper.deleteAUser(user1.getId());          //删除user1
        Log.i(TAG, helper.readAUser(1).toString()); //显示id为1的用户

结果


结果

上面的代码中,分别打印了三次log。
第一次使用id为1的用户;
第二次是年龄被修改为30的用户;
第三次是被删除的用户,因为用户不存在了,所以没有第三条log
(由于helper.readAUser(1)没有获取到数据,返回null,接着使用了toString()出现空指针异常,闪退了,做了一个反面教材~~)。
不管怎么说,这次的目的达到了,增删查改都ok了。

小结

使用SQLite就是在本地建了一个数据库,使用数据库中的表来保存数据。SQLite对数据的操作十分灵活,不过相比SharedPreferencesFile在使用上要复杂一些,而且要一点的数据库基础。

附: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 {
    /**
     * 数据库版本,需要升级数据库时只要加一即可
     */
    private static final int DATABASE_VERSION = 1;
    /**
     * 数据库名
     */
    private static final String DATABASE_NAME = "mySQLite.db";

    /**
     * 构造方法
     * 每次创建DatabaseHelper对象时,若本应用无该数据库,则新建数据库并调用onCreate方法;
     * 若该数据库已创建则直接使用已存在的数据库且跳过onCreate方法
     * factory : 当打开的数据库执行查询语句的时候 会创建一个Cursor对象, 这时会调用Cursor工厂类 factory, 可以填写null默认值
     * @param context   上下文
     */
    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    /**
     * 创建数据库是时调用(只被调用一次)
     * @param db    数据库
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建user表,属性:id(用户id,主键)、name(姓名)、age(年龄)
        db.execSQL("CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(10),age INTEGER)");
    }

    /**
     * 跟新数据库时调用
     * @param db            数据库
     * @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)");
    }

    /**
     * 插入一条数据
     * @param user  用户对象
     */
    public void insertAUser(User user) {
        //如果要对数据进行更改,就调用此方法得到用于操作数据库的实例,该方法以读和写方式打开数据库
        SQLiteDatabase database = getWritableDatabase();
        //向user表插入一条数据
        database.execSQL(
                "INSERT INTO user(name, age) VALUES(?,?)",
                new Object[]{user.getName(), user.getAge()});
    }

    /**
     * 更新一条用户数据
     * @param user  用户对象
     */
    public void updateAUser(User user) {
        SQLiteDatabase database = getWritableDatabase();
        //根据id更新一条数据
        database.execSQL(
                "UPDATE user SET name=?, age=? WHERE id=?",
                new Object[]{user.getName(), user.getAge(), user.getId()});
    }

    /**
     * 根据id删除一条数据
     * @param id    用户id
     */
    public void deleteAUser(Integer id) {
        SQLiteDatabase database = getWritableDatabase();
        //根据id删除一条数据
        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;
    }

    /**
     * 读取一条数据
     * @param id    用户id
     * @return      用户对象
     */
    public User readAUser(Integer id) {

        //如果只对数据进行读取,建议使用此方法
        SQLiteDatabase database = getReadableDatabase();
        Cursor cursor  = database.rawQuery(
                "SELECT * FROM user WHERE id=?",
                new String[]{id.toString()});
        if (cursor.moveToFirst()) {
            //读取数据,并返回
            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 {
            //未读出数据,返回空数据
            return null;
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容