zoukankan      html  css  js  c++  java
  • Android 数据存储总结-数据库SQLite的具体使用(附参考代码)

    我最近做项目用到了这个SQLite本地数据库,所以写篇博客总结一下,希望也能对小白有所帮助

    • 什么时候用SQLite(有固定规则的,大量的数据要保存时)

    SharedPreferences是一种轻型的数据存储方式,在保存数据的时候其实存储的是key-value对,类似于Map。存储位置:/data/data/应用包名/shared_prefs/文件名.xml。通常用来存储一些简单的配置信息。实际开发中,SharedPreferences共享参数经常存储的数据有App的个性化配置信息、用户使用App的行为信息、临时需要保存的片段信息等。

    简单且孤立的数据可保存在SharedPreferences。若是复杂且相互间有关的数据,则要保存在数据库中。(有固定规则的,大量的数据保存在数据库中)

    文本形式的数据可保存在SharedPreferences。若是二进制数据,则要保存在文件中。(没有固定规则的,大量的数据保存在文件中)

    haredPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其只能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。

    SQLite是一个小巧的嵌入式数据库,使用方便、开发简单。它只是一个嵌入式的数据库引擎。在Android里,提供了SQLiteDatabase类,该类的一个对象就表明一个数据库,其实在底层就是一个文件。默认存储位置:/data/data/<PackageName>/databases

    • SQLiteDatabase数据库管理类(直接对数据库进行操作)

     SQLiteDatabase是SQLite的数据库管理类,开发者可以在活动页面代码或任何能取到Context的地方获取数据库实例。然后通过SQLiteDatabase提供的一些API来对数据库进行操作:

    // 创建名叫test.db的数据库。数据库如果不存在就创建它,如果存在就打开它
    SQLiteDatabase db = openOrCreateDatabase(getFilesDir() + "/test.db", Context.MODE_PRIVATE, null);
    // 删除名叫test.db数据库
    // deleteDatabase(getFilesDir() + "/test.db");

    调用该类API要用到SQL语句,SQLite的多数SQL语法与Oracle一样,可以到菜鸟网上查阅:https://www.runoob.com/sqlite/sqlite-tutorial.html

    SQLiteDatabase中常用的API:

    1. 管理类,用于数据库层面的操作。

    • openDatabase:打开指定路径的数据库。
    • isOpen:判断数据库是否已打开。
    • close:关闭数据库。
    • getVersion:获取数据库的版本号。
    • setVersion:设置数据库的版本号。

    2. 事务类,用于事务层面的操作。

    • beginTransaction:开始事务。
    • setTransactionSuccessful:设置事务的成功标志。
    • endTransaction:结束事务。执行本方法时,系统会判断是否已执行setTransactionSuccessful,如果之前已设置就提交,如果没有设置就回滚。

    3. 数据处理类,用于数据表层面的操作。

    • execSQL:执行拼接好的SQL控制语句。一般用于建表、删表、变更表结构。
    • delete:删除符合条件的记录。
    • update:更新符合条件的记录。
    • insert:插入一条记录。
    • query:执行查询操作,返回结果集的游标。
    • rawQuery:执行拼接好的SQL查询语句,返回结果集的游标。

    但是直接通过SQLiteDatabase进行操作数据库非常不方便,必须小心不能重复地打开数据库,处理数据库的升级也很不方便。

    因此Android提供了一个辅助工具—— SQLiteOpenHelper,我们可以通过SQLiteOpenHelper这个数据库帮助器来安全方便地打开、升级数据库。

    • SQLiteOpenHelper数据库帮助器(安全方便地打开、升级数据库)

    使用方法:

    新建一个继承自SQLiteOpenHelper的数据库操作类,提示重写onCreate和onUpgrade两个方法。

    其中,onCreate方法只在第一次打开数据库时执行,在此可进行表结构创建的操作;

    onUpgrade方法在数据库版本升高时执行,因此可以在onUpgrade函数内部根据新旧版本号进行表结构变更处理。

    例如:

    //数据库帮助器SQLiteOpenHelper
    public class MySqliteHelper extends SQLiteOpenHelper {
    
        public MySqliteHelper(Context context,
                              String name,
                              SQLiteDatabase.CursorFactory factory,
                              int version) {
            super(context, name, factory, version);
        }
        public MySqliteHelper(Context context){
            super(context,Constant.DATABASE_NAME,null,Constant.DATABASE_VERSION);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            // TODO 创建数据库后,对数据库的操作
         // sql中Constant是用来存放一些关于数据库的常量的类
         // 类型有:Integer、text文本、varchar(n)、real浮点型、blob二进制类型
    String sql = "create table if not exists "+Constant.TABLE_NAME+"("+ Constant.ID+" Integer primary key ,"+ Constant.USER+" text,"+ Constant.DATE+" text,"+ Constant.TIME+" text,"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO 更改数据库版本的操作,根据新旧版本号进行表结构变更处理,当打开数据库时传入版本号与当前不同会调用此方法
        //在使用中只需要调用构造函数时把版本号参数version改大即可
        db.execSQL("drop table if exists " + Constant.TABLE_NAME);
        onCreate(db);
      } 

      @Override
      public void onOpen(SQLiteDatabase db) {

        super.onOpen(db); // TODO 每次成功打开数据库后首先被执行
      }
    }
    • 数据库操作的工具类(封装保证数据库安全的必要方法和操作数据库记录的方法)

    在这个类中,封装保证数据库安全的必要方法,包括获取单例对象、打开数据库连接、关闭数据库连接,并且封装对表记录进行增加、删除、修改、查询的操作方法。

    获取单例对象:确保App运行时数据库只被打开一次,避免重复打开引起错误。

    打开数据库连接:SQLite有锁机制,即读锁和写锁的处理;故而数据库连接也分两种,读连接可调用SQLiteOpenHelper的getReadableDatabase方法获得,写连接可调用getWritableDatabase获得。

    关闭数据库连接:数据库操作完毕后,应当调用SQLiteDatabase对象的close方法关闭连接。

    例如:

    /**
     * DbManger 操作我们数据库的工具类  我们一般写成单例模式
     * 单例模式 :  在整个应用程序中  不管什么地方(类)  获得的都是同一个对象实例*/
    public class DbManger {
        private static final String TAG = "DbManger";
        private static MySqliteHelper helper; //建立一个数据库对象
        //表名
        private String table_name ="p_data";
        
       /**单例模式:不能让每一个类都能new一个,那样就不是同一个对象了,所以首先构造函数要私有化,以上下文Context作为参数 * @param ctx 本类的上下文对象 * @return */ private DbManger(Context ctx){ //由于数据库只需要调用一次,所以在单例中建出来 helper= new MySqliteHelper(ctx); } //public static 为静态类型,要调用就要有一个静态的变量,为私有的 private static DbManger instance; //既然该类是私有的 那么别的类就不能够调用 那么就要提供一个public static(公共的 共享的)的方法 //方法名为getInstance 参数为上下文 返回值类型为这个类的实例   //要加上一个synchronized(同步的)如果同时有好多线程 同时去调用getInstance()方法 就可能会出现一些创建多个DBManger的现象 public static synchronized DbManger getInstance(Context ctx){ //如果为空 就创建一个, 如果不为空就还用原来的 这样整个应用程序中就只能获的一个实例 if(instance == null){ instance = new DbManger(ctx); } return instance; }//常用方法 增删改查 /** * 添加数据 至数据库 * @param USER 用户名 DATE 日期 TIME 时间 */ public void addData(String USER,String DATE,String TIME){ //获得一个可写的数据库的一个引用 SQLiteDatabase db = helper.getWritableDatabase(); ContentValues values= new ContentValues(); values.put(Constant.USER, USER); values.put(Constant.DATE, DATE); values.put(Constant.TIME, TIME);// 参数一:表名,参数三,是插入的内容 // 参数二:只要能保存 values中是有内容的,第二个参数可以忽略 db.insert(table_name, null, values); Log.d(TAG, "addData: 数据保存成功:"+USER+""+DATE+""+TIME); } /** * 删除用户 * @param user */ public void deletebyuser(String user){ SQLiteDatabase db = helper.getWritableDatabase(); //表名 删除的条件 db.delete(table_name, "user = ?", new String[] {user}); } /** * 删除某条记录 * @param id */ public void deletebyid(int id){ SQLiteDatabase db = helper.getWritableDatabase(); //表名 删除的条件 db.delete(table_name, "id = ?", new String[] {Integer.valueOf(id).toString()}); } /** * //查找 每一个黑名单都有 号码和模式 先把号码和模式封装一个bean * 获得所有的黑名单 * @param user 用户名 * @param pageIndex 页数 * @param pageSize 每页显示的行数 * @return */ //分页查询 修改 p_data是一个新定义的,用来存放一系列数据的类 public List<p_data> getAllData(String user,int pageIndex, int pageSize){//创建集合对象 List<p_data> data = new ArrayList<p_data>(); SQLiteDatabase db = helper.getReadableDatabase();
    //Cursor cursor = db.query(p_data, null, null, null, null, null, null);//查询全部数据
        
    //order by _id desc 根据_id倒叙排列 使新添加的数据在查询时显示上面。根据用户名查询
    //分页查询:pageSize每页显示的数目,pageIndex页数 Cursor cursor = db.rawQuery("select * from p_data where user = ? order by id desc limit "+pageSize +" offset "+((pageIndex-1)*pageSize)+";", new String[]{user});

         //返回的 cursor 默认是在第一行的上一行 //遍历 while(cursor.moveToNext()){// cursor.moveToNext() 向下移动一行,如果有内容,返回true String TIME = cursor.getString(cursor.getColumnIndex("time")); // 获得time 这列的值 String DATE = cursor.getString(cursor.getColumnIndex("date")); // 获得date 这列的值//将查找到的数据封装到bean中 p_data bean = new p_data(user,DATE,TIME); //封装的对象添加到集合中 data.add(bean); } //关闭cursor cursor.close(); //SystemClock.sleep(1000);// 休眠2秒,查找出的数据比较多、比较耗时的情况下使用 Log.d(TAG, "getAllData: 查询数据库数据"+data ); return data; } /** * 获得数据的数量 */ public int getNumCount(String user){ SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.query(table_name, new String[] {"count(*)"}, "user = ?",new String[] {user}, null, null, null, null); cursor.moveToNext(); int count = cursor.getInt(0);// 仅查了一列,count(*) 这一刻列 cursor.close(); return count; } }

    可被SQLite直接使用的数据结构是ContentValues类,类似于映射Map,提供put和get方法用来存取键值对。区别之处在于ContentValues的键只能是字符串”。ContentValues主要用于记录增加和更新操作,即SQLiteDatabase的insert和update方法。

    对于查询操作来说,使用的是另一个游标类Cursor。调用SQLiteDatabase的query和rawQuery方法时,返回的都是Cursor对象,因此获取查询结果要根据游标的指示一条一条遍历结果集合,Cursor的常用方法:

    1. 游标控制类方法,用于指定游标的状态。

    • close:关闭游标。
    • isClosed:判断游标是否关闭。
    • isFirst:判断游标是否在开头。
    • isLast:判断游标是否在末尾。

    2. 游标移动类方法,把游标移动到指定位置。

    • moveToFirst:移动游标到开头。
    • moveToLast:移动游标到末尾。
    • moveToNext:移动游标到下一条记录。
    • moveToPrevious:移动游标到上一条记录。
    • move:往后移动游标若干条记录。
    • moveToPosition:移动游标到指定位置的记录。

    3. 获取记录类方法,可获取记录的数量、类型以及取值。

    • getCount:获取结果记录的数量。
    • getInt:获取指定字段的整型值。
    • getFloat:获取指定字段的浮点数值。
    • getString:获取指定字段的字符串值。
    • getType:获取指定字段的字段类型。
    • 在Activity、fragment中使用SQLite

    创建数据库(onCreateView或onCreate中):

    private DbManger dbManger;

    dbManger = DbManger.getInstance(view.getContext());//fragment dbManger = DbManger.getInstance(this);//activity

    然后通过dbManger调用所需的操作函数即可。

    • 补充:保存数据的类

    public class p_data {
    
        private String USER;
        private String DATE;
        private String TIME;
    
        public Nbp_data( String USER, String DATE, String TIME) {
            this.USER = USER;
            this.DATE = DATE;
            this.TIME = TIME;
        }
    
        public void setDATE(String DATE) {
            this.DATE = DATE;
        }
    
        public void setUSER(String USER) {
            this.USER = USER;
        }
    public String getUSER() {
            return USER;
        }
      public String getDATE() {
            return DATE;
        }
        public String getTIME() {
            return TIME;
        }
    }
    • 补充:保存常量的类

    public class Constant {
    
        public static final String DATABASE_NAME = "info.db";  // 数据库名称
        public static final int DATABASE_VERSION = 1;          //数据库版本
        public static final String TABLE_NAME = "p_data";     //数据库表名
        /**
         * id、user、date以下是数据库表中的字段
         */
        public static  final String ID = "id";                //id主键
        public static  final String USER = "user";            //用户
        public static final String DATE = "date";             //日期
        public static final String TIME = "time";             //时间
    }

    参考:

    Android Studio开发实战:从零基础到App上线  欧阳燊著 清华大学出版社

    CSDN博主:「快乐的金豆」 Android 数据储存的方式之本地数据库储存  https://blog.csdn.net/lijinweii/java/article/details/73930260

    CSDN博主:「小鹿动画学编程」 搭建Android本地数据库(SQLite)的详细讲解  https://blog.csdn.net/qq_36903042/java/article/details/79772268

  • 相关阅读:
    一行代码解决各种IE兼容问题,IE6,IE7,IE8,IE9,IE10(如果今天你的老板还在要求你兼容IE6~8,别犹豫,辞职吧。)
    HTML元素分类【三种类型】
    React-Native 学习笔记-Android开发平台-开发环境搭建
    常用原生JS函数和语法集合
    jQuery选择器总结
    jQuery选择器大全
    Sublime Text 3 的HTML代码格式化插件Tag
    用CSS画三角形
    纯CSS绘制三角形(各种角度)
    纯CSS写三角形-border法[晋级篇01]
  • 原文地址:https://www.cnblogs.com/XIEjm/p/12810522.html
Copyright © 2011-2022 走看看