欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 数据存储笔记-数据库SQLite

程序员文章站 2023-02-21 19:11:28
什么时候用SQLite? SQLiteDatabase数据库管理类。 SQLiteOpenHelper数据库帮助器。 数据库操作的工具类:在这个类中,封装保证数据库安全的必要方法,包括获取单例对象、打开数据库连接、关闭数据库连接,并且封装对表记录进行增加、删除、修改、查询的操作方法。 ......

我最近做项目用到了这个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一样,可以到菜鸟网上查阅:

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";             //时间
}