一篇好文之Android数据库 SQLite全解析

一篇好文之Android数据库 SQLite全解析_第1张图片
这篇文章是数据库系列篇文章的第一篇,主要讲Android Sqlite数据库存储,后面陆续出GreenDao,LitePal, Realm,wcdb的文章,一如既往,如果遇到任何关于Android中SQLite的问题,都可以直接在我的文章底部留言,或者直接在我的公众号aserbao留言,文章会持续更新,希望这篇文章能为大家提供到帮助!如果觉得文章对你有用,就帮忙点个赞,若觉得文章写得不好之处望指出,必将加以修正!
一篇好文之Android数据库 SQLite全解析_第2张图片

这篇文章主要讲SQlite数据库存储,从数据库建表到数据库的增删改查操作,再到数据库升级操作,最后是文章总结及参考链接

文章目录

    • 项目效果地址:
    • SQlite
      • 1. 创建数据库
      • 2. 创建一个数据库存储对象
      • 3. 创建一个数据库控制器实现增删改查
        • 1. 增
        • 2. 删
        • 3. 改
        • 4. 查
      • 4. 数据库的升级
    • 问题
      • 查询问题
    • 参考链接

项目效果地址:

一篇好文之Android数据库 SQLite全解析_第3张图片
AserbaosAndroid

SQlite

1. 创建数据库

Android中使用SQlite,需要自己创建库,建表,添加数据!好在Android中提供了SQLiteOpenHelper类来帮助创建使用数据库,我们只需要继承这个类就可以实现数据库的创建和对数据的操作了!Android 中创建数据库需要通过如下几部:

  1. 创建一个类继承SQLiteOpenHelper,需要实现其三个方法:
    • 构造方法:需要给SQLiteOpenHelper传递四个参数:(上下文,数据库名,游标工厂(通常为null),当前数据库版本号);
    • onCreate(): 表的创建,初始化操作
    • onUpgrade(): 表升级
    • 还有:onDowngrade(): 表降级,onOpen:每次打开数据库,onBeforeDelete:
public class ThingManagerDBOpenHelper extends SQLiteOpenHelper {
    public static final String DB_NAME = "mysql.db";
    private static final int VERSION = 1;
    public ThingManagerDBOpenHelper(Context context) {
        super(context, DB_NAME, null, VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS "
                + ThingDBController.TABLE_NAME
                + String.format(
                "("
                        + "%s INTEGER PRIMARY KEY AUTOINCREMENT, "
                        + "%s VARCHAR, "
                        + "%s INTEGER"
                        +")"
                , ThingManagerDBModel.ID
                , ThingManagerDBModel.MESSAGE
                , ThingManagerDBModel.TIME
        )) ;
    }


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

说下SQlite的数据类型 :

作用
NULL: 这个值为空值
VARCHAR(n): 长度不固定且其最大长度为 n 的字串,n不能超过 4000。
CHAR(n): 长度固定为n的字串,n不能超过 254。
INTEGER: 值被标识为整数,依据值的大小可以依次被存储为1,2,3,4,5,6,7,8.
REAL: 所有值都是浮动的数值,被存储为8字节的IEEE浮动标记序号.
TEXT: 值为文本字符串,使用数据库编码存储(TUTF-8, UTF-16BE or UTF-16-LE).
BLOB: 值是BLOB数据块,以输入的数据格式进行存储。如何输入就如何存储,不改 变格式。
DATA: 包含了 年份、月份、日期。
TIME: 包含了 小时、分钟、秒。

2. 创建一个数据库存储对象

public final class ThingManagerDBModel {
    public static final String TABLE_NAME = "mysql_thing";
    public static final String ID = "_id";
    public static final String MESSAGE = "message";
    public static final String TIME = "time";

    int id;
    String message;
    long time;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }

    public ContentValues toContentValues(){
        ContentValues cv = new ContentValues();
        cv.put(MESSAGE, message);
        cv.put(TIME, time);
        return cv;
    }
}

3. 创建一个数据库控制器实现增删改查

1. 增

  1. 使用Android APi来实现增加数据
 public boolean insertApi(int id, String message, long time){
        ThingManagerDBModel dbModel = new ThingManagerDBModel();
        if(id >= 0) {
            dbModel.id = id;
        }
        dbModel.message = message;
        dbModel.time = time;
        final boolean success = db.insert(TABLE_NAME, null, dbModel.toContentValues()) != -1;
        dbClose();
        return success;
    }
  1. 使用Sql语句实现增加数据
 public void insertRaw(String message, long time){
        String sql = " insert into " + TABLE_NAME + "(message,time) values(?,?)";
        Object[] args = {message,time};
        db.execSQL(sql,args);
        dbClose();
    }

2. 删

  1. 使用Api
  public boolean deleteApi(String whereClause,String[] whereArgs){
        boolean sucess = db.delete(TABLE_NAME, whereClause,whereArgs) != -1;
        dbClose();
        return sucess;
    }
  1. 使用Sql语句
 public void deleteRaw(String message){
        String sql = "delete from "+TABLE_NAME + " where message = ?";
        Object[] args = {message};
        db.execSQL(sql,args);
        dbClose();
    }

3. 改

  1. 使用api
public boolean updateApi(int id,String message,long time){
        ThingManagerDBModel dbModel = new ThingManagerDBModel();
        if(id >= 0) {
            dbModel.id = id;
        }
        dbModel.message = message;
        dbModel.time = time;
        boolean success = db.update(TABLE_NAME, dbModel.toContentValues(), "_id = ?", new String[]{String.valueOf(id)}) != -1;
        dbClose();
        return success;
    }
  1. 使用Sql条件修改
public void updateRaw(int id,String message,long time){
        String sql = "update "+TABLE_NAME + " set message = ?,time = ? where _id = ?";
        Object[] args = {message,time,id};
        db.execSQL(sql,args);
        dbClose();
    }

4. 查

  1. 使用Api
/**
     * @param cloums 要查询的字段
     * @param selection 查询条件
     * @param selectionArgs 填充查询条件的值
     * @return
     */
    public List queryApi(String[] cloums,String selection,String[]  selectionArgs){
        try {
            Cursor c = db.query(TABLE_NAME, cloums, selection, selectionArgs, null, null, null);
            ArrayList arrayList = new ArrayList<>();
            if (!c.moveToLast()) {
                return arrayList;
            }
            do {
                Thing model = new Thing();
                model.setId(c.getInt(c.getColumnIndexOrThrow(ThingManagerDBModel.ID)));
                model.setTime(c.getLong(c.getColumnIndexOrThrow(ThingManagerDBModel.TIME)));
                model.setMessage(c.getString(c.getColumnIndexOrThrow(ThingManagerDBModel.MESSAGE)));
                arrayList.add(model);
            } while (c.moveToPrevious());
            c.close();
            return arrayList;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            dbClose();
        }

        return new ArrayList<>();
    }

  1. 使用sql条件
 public List queryRawById(String  id){
 	//cursor获取的一定是在这里申明的查询条件值
        String sql = "select _id,message,time from "+TABLE_NAME + " where _id = ?";
        Cursor cursor = db.rawQuery(sql, new String[]{id});
        ArrayList arrayList = new ArrayList<>();
        if (!cursor.moveToLast()) {
            return arrayList;
        }
        do {
            Thing model = new Thing();
            model.setId(cursor.getInt(cursor.getColumnIndex(ThingManagerDBModel.ID)));
            model.setTime(cursor.getLong(cursor.getColumnIndex(ThingManagerDBModel.TIME)));
           model.setMessage(cursor.getString(cursor.getColumnIndexOrThrow(ThingManagerDBModel.MESSAGE)));
            arrayList.add(model);
        } while (cursor.moveToPrevious());
        cursor.close();
        dbClose();
        return arrayList;
    }

4. 数据库的升级

在开发的过程中,我们避免不了需要修改数据库结构,添加字段或者删除字段!我们通过增加传递给SQLiteOpenHelper的版本值,得到onUpgrade方法的回调来实现对数据库的操作来进行升级。这里需要注意的是,如果用户安装版本1之后直接跳装版本3,这时候我们就需要在onUpgrade方法中通过oldVersion来进行每一个版本的逐渐升级,方法如下:


public class ThingManagerDBOpenHelper extends SQLiteOpenHelper {
    public static final String DB_NAME = "mysql.db";
    private static final int VERSION = 3;
    ……
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch (oldVersion){
            case 1:
                upToDbVersion2(db);
            case 2:
                upToDbVersion3(db);
            default:
              break;
        }
    }
    public void upToDbVersion2(SQLiteDatabase db){
        db.execSQL("ALTER TABLE " + ThingDBController.TABLE_NAME + " ADD COLUMN add_user_name text");
    }

    public void upToDbVersion3(SQLiteDatabase db) {
        ContentValues values = new ContentValues();
        values.put("message", "版本升级后的数据");
        db.update(ThingDBController.TABLE_NAME, values, null, null);
    }
}

问题

查询问题

Cursor只会拥有你查询的数据,如果在查询条件里面没有申请,Cursor里面就不会包含这个值,就会出现如下异常:
错误写法:

 String sql = "select message,time from "+TABLE_NAME + " where _id = ?";//条件里面没有申请查询_id的值
 ……something……
 model.setId(cursor.getInt(cursor.getColumnIndex(ThingManagerDBModel.ID)));//在这里提取会报异常

正确写法:

 String sql = "select  _id,message,time from "+TABLE_NAME + " where _id = ?";//条件里面没有申请查询_id的值
 ……something……
 model.setId(cursor.getInt(cursor.getColumnIndex(ThingManagerDBModel.ID)));//这里进行id值的提取

异常:

  java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
        at android.database.CursorWindow.nativeGetLong(Native Method)
        at android.database.CursorWindow.getLong(CursorWindow.java:513)
        at android.database.CursorWindow.getInt(CursorWindow.java:580)
        at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:69)
        at com.aserbao.aserbaosandroid.functions.database.mySql.beans.ThingDBController.queryRawById(ThingDBController.java:109)
        at com.aserbao.aserbaosandroid.functions.database.mySql.MySqlActivity.queryData(MySqlActivity.java:70)
        at com.aserbao.aserbaosandroid.functions.database.base.DataBaseBaseActivity.onViewClicked(DataBaseBaseActivity.java:85)
        at com.aserbao.aserbaosandroid.functions.database.base.DataBaseBaseActivity_ViewBinding$2.doClick(DataBaseBaseActivity_ViewBinding.java:48)
        at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
        at android.view.View.performClick(View.java:6291)
        at android.view.View$PerformClick.run(View.java:24931)
        at android.os.Handler.handleCallback(Handler.java:808)
        at android.os.Handler.dispatchMessage(Handler.java:101)
        at android.os.Looper.loop(Looper.java:166)
        at android.app.ActivityThread.main(ActivityThread.java:7425)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

参考链接

  1. Android 开发中使用 SQLite 数据库
  2. Android数据库Sqlite的基本用法及升级策略

你可能感兴趣的:(Android,一篇好文)