美文网首页
一篇好文之Android数据库 SQite全解析

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

作者: aserbao | 来源:发表于2018-10-23 20:54 被阅读41次
    数据库SQLite.jpg

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


    qrcode_for_gh_2886db5aaf83_258.jpg

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

    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<Thing> queryApi(String[] cloums,String selection,String[]  selectionArgs){
            try {
                Cursor c = db.query(TABLE_NAME, cloums, selection, selectionArgs, null, null, null);
                ArrayList<Thing> 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<Thing> queryRawById(String  id){
        //cursor获取的一定是在这里申明的查询条件值
            String sql = "select _id,message,time from "+TABLE_NAME + " where _id = ?";
            Cursor cursor = db.rawQuery(sql, new String[]{id});
            ArrayList<Thing> 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数据库 SQite全解析

          本文链接:https://www.haomeiwen.com/subject/ffhzzftx.html