zoukankan      html  css  js  c++  java
  • Android开发-之SQLite数据库

      之前我们讲了如何将数据存储在文件中,那么除了这种方式呢,就是我们常见的大家都知道的将数据存储在数据库当中了。

      将数据存储在数据库中的优势:

        1)存储在数据库中的数据更加方便操作,比如增、删、改、查等

        2)可以实现事务的回滚,比如银行转账等

        3)方便维护,可读性高

        4)资源占用少,性能高

        5)……

      SQLite数据库在我们日常生活中随处不见了,比如我们的手机~现在市场上的手机都是用SQLite数据库作为数据的存储的。

      以及我们常看见的智能家居,也是用SQLite数据库去记录数据的。以及我们经常用到的桌面程序,比如QQ、迅雷等。

    一、SQLite数据库概念及优缺点

      SQLite数据库是一套开源的嵌入式数据库引擎,它的每个数据库都是以单个文件的形式存在

      这些数据以B-Tree的数据结构的形式存储在磁盘上面。

      SQLite数据库就是一个很小的、可以直接打开运行的文件,而其他的数据库都是一个大型的应用程序。

      使用SQLite的优势:

        1、SQLite支持大多数的sql标准语句

          增、删、改、查、事务等等,所以这里就不详细的说这个了……

        2、轻量级

          可以说是袖珍型,然而小小的SQLite却可以支持高达2TB大小的数据库

        3、检索速度快

        4、动态数据模型(弱类型)

          SQLite数据库支持

            NULL:空值

            INTEGER:整数型

            REAL:浮点型

            TEXT:字符串文本

            BLOB:二进制对象

          5个基本数据类型。

          之所以称之为“弱类型”,是因为插入数据的时候不管是什么数据类型都会自动的转化。

          注意:当INTEGER的约束为PRIMARY KEY时,就必须是整数不会自动转换,否则就会报错!

        5、SQLite数据库在使用前不需要安装配置,也不需要启用进程来启动、关闭数据库

        6、占用系统资源少

        7、跨平台

          它可以在多个操作系统下使用而不需要针对某一个操作系统独立编写代码,也就是说它在各各操作系统的数据层是相同的;

          同时也是SQLite数据库内在机制决定的,SQL数据库是运行在SQLite虚拟机上面的,

          在虚拟机上面会直接转编译成不同操作系统的数据模型。

      SQLite的缺陷在于:

        1、不支持大型项目

        2、一部分SQL标准语句不支持,但是这些语句一般不会用到……

        3、安全性相对于其他大型数据库差

          就要比我们的Android手机,只要获取到root权限,那么也就是证明可以为所欲为了……

          那么Android怎么来加强它的安全性呢?

            a、提高程序的安全验证

            b、加强代码的严谨性

            c、权限管理

     

      介于SQLite数据库的优势,很多的桌面应用程序都用它来存储该应用程序的数据;

      当然,我们的Android以及iPhone的产品链也几乎都是运用SQLite数据库。

    二、Android中的实现

       1、使用原生的方法对数据库进行简单的操作

        也就是直接写SQL代码

        a、定义一个方法,继承SQLiteOpenHelper类。并实现onCreate和onUpgrade方法,重写自定义的方法。

          重写自定义的方法:

            1)参数有很多,那么这里简单的只需要context参数就好了。

            2)super参数:

              context:上下文

              name:数据库名称

              factory:目的创建cursor对象

              version:数据库版本,一般从1开始

          onCreate方法:

            1)当数据库第一次创建时使用,如果是其次的就是打开

            2)适合做表结构的初始化

          onUpgrade方法:

            1)当数据库的版本升级时使用

            2)适合做表结构的更新

          execSQL:

            要执行的sql语句,这里适用于增、删、改

    public class MyOpenHelper extends SQLiteOpenHelper {
    
        /**
         * 
         * @param context 上下文
         * name 数据库的名称
         * factory 目的创建cursor对象
         * version 数据库版本    从1开始
         */
        public MyOpenHelper(Context context) {
            super(context, "test_1.db", null, 3);
        }
    
        /**
         * 当数据库第一次创建是使用
         * 这个方法特别适合做表结构的初始化   创建表就是写sql语句
         */
        @Override
        public void onCreate(SQLiteDatabase db) {
            
            db.execSQL("create table test_info(id integer primary key autoincrement,name varchar(20))");
        }
    
        /**
         * 当数据库版本升级时使用
         * 这个方法适合做表结构的更新
         */
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            
            db.execSQL("alter table test_info add phone varchar(20)");
        }
    
    }

        b、必须要注意数据库的降级onDowngrade,降级的设计关键点

          1)考虑云端要保存用户【自定义数据、行为习惯】。专业术语profile-->>提高用户黏度

          2)考虑当前的最低版本要求-->>降低维护成本

          3)尽可能本地的数据转移(所有新版本,都不删除字段)-->尽可能把未知变已知

          4)降级很可能会失败,所以我们一般 try-catch;当降级成功就是try块的语句,失败之后就执行catch块的语句

          5)SQLiteDatabase(执行语句)、oldVersion(老版本号)、newVersion(新版本号)

    /* 模拟从3.0 降低会2.0 */
        @Override
        public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            //正常来讲大于2.0的,应该有test_info 这张表,且2.0有的字段,3.0都有
            try {
                //第一、先把test_info 未来的表,改名
                String rename_sql = "alter table test_info rename to test_info_bak";
                db.execSQL(rename_sql);
                Log.i("down", "1.改名成功");
                //第二、建立2.0的表结构
                String sql_message = "create table test_info (id int primary key,tou1  varchar(50),userName varchar(50),
                        lastMessage varchar(50),datetime varchar(50))"; db.execSQL(sql_message); Log.i("down", "2.建立2.0表结构成功"); //第三、把备份的数据,copy到 新建的2.0的表 String sql_copy = "insert into test_info select id,tou1,userName,lastMessage,datetime from test_info_bak"; db.execSQL(sql_copy); Log.i("down", "3.copy到用户数据到 2.0的表"); //第四、把备份表drop掉 String drop_sql = "drop table if exists test_info_bak"; db.execSQL(drop_sql); Log.i("down", "4.把备份表drop掉"); } catch (Exception e) { //失败 Log.i("hi", "降级失败,重新建立"); String sql_drop_old_table = "drop table if exists test_info"; String sql_message = "create table test_info(id integer primary key autoincrement,name varchar(20),phone varchar(20))"; String sql_init_1 = "insert into test_info values (1,'abc','130000')"; String sql_init_2 = "insert into test_info values (2,'abc','134444')"; db.execSQL(sql_drop_old_table); db.execSQL(sql_message); db.execSQL(sql_init_1); db.execSQL(sql_init_2); } }

        c、创建MyOpenHelper对象

    myOpenHelper = new MyOpenHelper(getApplicationContext());
            
    //打开或是创建数据库     如果第一次就是创建,其次就是打开
    //SQLiteDatabase sqliteDatabase = myOpenHelper.getWritableDatabase();
    //打开或是创建数据库     如果第一次就是创建,其次就是打开     如果磁盘满了就返回只读
    //SQLiteDatabase sqliteDatabase = myOpenHelper.getReadableDatabase();

        d、增加数据

    //获取数据库对象
    SQLiteDatabase db = myOpenHelper.getWritableDatabase();
    //执行添加一条sql语句
    db.execSQL("insert into test_info(name,phone) values(?,?)",new Object[]{"zhangsan","138888888"});
    //数据库用完要关闭
    db.close();

        e、删除数据

    SQLiteDatabase db = myOpenHelper.getWritableDatabase();
    db.execSQL("delete from test_info where name=?",new Object[]{"zhangsan"});
    db.close();

        f、修改数据

    SQLiteDatabase db = myOpenHelper.getWritableDatabase();
    db.execSQL("updata test_info set phone=? where name=?",new Object[]{"13777777777","zhangsan"});
    db.close();

        g、查询数据

    SQLiteDatabase db = myOpenHelper.getWritableDatabase();
            
            Cursor cursor = db.rawQuery("select * from test_info", null);
                  
            if(cursor!=null&&cursor.getCount()>0){
                while(cursor.moveToNext()){
                    //columnIndex代表列的索引
                    String name = cursor.getString(1);
                    String phone = cursor.getString(2);
                }
            }

      2、使用Google封装好的api对数据进行简单操作

        Google工程师给我们封装好了的一些方法让我们直接调用,但是其实在底层也就是将这些字符串进行拼接成完整的sql语句。

        a、增加数据

          ContentValues  内部封装好的一个map集合,map集合是以<key,value>的形式存储数据的。

          insert参数说明

            table:表名

            key:对应列的名字

            value:对应的值

          put参数说明

            key:增加的列名字

            value:对应的值

     

    //获取数据库对象
    SQLiteDatabase db = myOpenHelper.getWritableDatabase();
    /**
    * table 表名
    * ContentValues 内部封装了一个map 
    * key:对应列的名字   
    * value:对应值
    */
    ContentValues values = new ContentValues();
    values.put("name", "wangwu");
    values.put("phone", "120");
    //返回值代表插入新行的id
    long insert = db.insert("test_info", null, values);//底层就是在拼接SQL语句
    //数据库用完要关闭
    db.close();
            
    if(insert>0){
        Toast.makeText(getApplicationContext(), "添加成功!", 3000).show();
    }else{
        Toast.makeText(getApplicationContext(), "添加失败!", 3000).show();
    }

        b、删除数据

          delete参数说明

            table:表名

            whereClause:要删除的是哪一列,根据什么删除

            whereArgs:这里返回的是一个数组对象,根据删除列的值

    SQLiteDatabase db = myOpenHelper.getWritableDatabase();
    //根据Google封装好的api删除
    int delete = db.delete("test_info", "name=?", new String[]{"wangwu"});
    db.close();
    Toast.makeText(getApplicationContext(), "删除了"+delete+"行", 2000).show();

        c、修改数据

          update参数说明

            table:表名

            value:就是ContentValues中的value

            whereClause:要修改的是哪一列,根据什么修改

            whereArgs:这里返回的是一个数组对象,根据修改列的值

    SQLiteDatabase db = myOpenHelper.getWritableDatabase();

    //根据Google封装好的api修改 ContentValues value = new ContentValues(); value.put("phone", "110"); //代表更新了多少行 int updata = db.update("test_info", value, "name=?", new String[]{"wangwu"}); db.close(); Toast.makeText(getApplicationContext(), "更新了"+updata+"行", 2000).show();

        d、查询数据

          query参数说明

            table:表名

            columns:查询的列

            selection:根据什么查询

            selectionArgs:查询的条件的值

            groupBy:分组

            having:查询条件,这里要区分having与where的区别!

            orderBy:排序

          moveToNext():遍历数据表中的数据

          cursor:Google工程师封装好的指针对象,用于遍历集合下标

    SQLiteDatabase db = myOpenHelper.getWritableDatabase();
            
    /**
     * 根据Google封装好的api查询
    * columns 代表你要查询的列
    * selection  根据什么查询phone
    */
    Cursor cursor = db.query("test_info", new String[]{"phone"}, "name=?", new String[]{"wangwu"}, null, null, null);
            
    if(cursor!=null&&cursor.getCount()>0){
         while(cursor.moveToNext()){
              String phone = cursor.getString(0);
              System.out.println("phone:" + phone);
         }
    }

      3、使用原生方法与封装好的api方法的优缺点

        a、原生方法优点

          1)可以更加灵活运用sql语句

          2)代码量可以减少,效率更高

        b、原生方法缺点

          1)容易写错sql代码

          2)不好维护

        c、封装好的优点

          1)不用直接写sql语句,减少了错误的概率

          2)方便维护

        d、封装好的缺点

          1)使程序更加笨重,效率低

          2)不方便数据的操作,不能灵活运用数据的操作语句

        不管是使用哪一种方法,都有它的好处和坏处,所以在实际开发中视实际情况而定,想用什么方法也都是可行的。

        建议:比较小型的程序推荐使用封装好的api,比较简单,可以提高开发效率

           比较大型的程序推荐使用原生方法,比较灵活,也可以提高程序效率

    三、总结

      1、使用SQLite的优缺点

      2、数据库的升级和降级(*****)

      3、使用原生方法对数据库进行简单操作

      4、使用Google封装好的api对数据库进行简单操作

      5、各自的优缺点

      6、Android和iPhone产品链的数据层是一样的

      

      ps:感兴趣的同学可以想想微信:

        在客户端的SQLite是怎么去实现的?

        在后台服务器使用什么去实现的,又是如何实现的?

        那么又要做到这些数据的交互呢?

        又是怎样去优化的呢?

  • 相关阅读:
    UVa 116 单向TSP(多段图最短路)
    POJ 1328 Radar Installation(贪心)
    POJ 1260 Pearls
    POJ 1836 Alignment
    POJ 3267 The Cow Lexicon
    UVa 1620 懒惰的苏珊(逆序数)
    POJ 1018 Communication System(DP)
    UVa 1347 旅行
    UVa 437 巴比伦塔
    UVa 1025 城市里的间谍
  • 原文地址:https://www.cnblogs.com/xiao-chuan/p/6140067.html
Copyright © 2011-2022 走看看