《Android本地存储SQLite优化》

一.简介

SQLite是一款开源的、嵌入式关系型数据库,第一个版本Alpha发布于2000年。SQLite在便携性、易用性、紧凑性、高效性和可靠性方面有着突出的表现。

SQLite和C/S模式的数据库软件不同,它是一款嵌入式数据库,没有独立运行的进程,与所服务的应用程序在应用程序进程空间内共生共存。它的代码与应用程序代码也是在一起的,或者说嵌入其中,作为托管它的程序的一部分。因此不存在数据库的客户端和服务器,使用SQLite一般只需要带上它的一个动态库,就可以享受它的全部功能。

数据库服务器在程序中的好处是不需要网络配置或管理。将数据库客户端与服务器运行在同一个进程中,可以省去不少的操作及麻烦:不用担心防火墙或者地址解析;不用浪费时间管理复杂的授权和权限;可以减少网络调用相关的消耗;可以简化数据库管理并使程序更容易部署。

SQLite数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但是只有一个可以写入数据。在某个进程向数据库执行写操作之前,必须获得独占锁定。在发出独占锁定后,其他的读写操作将不会再发生。

此外,SQLite数据库中的所有信息(比如表、视图、触发器等)都包含在一个文件内,方便管理和维护。SQLite数据库还支持大部分操作系统,除电脑上使用的操作系统之外,很多手机上使用的操作系统同样可以运行。同时,SQLite数据库还提供了多语言的编程接口,供开发者使用。

二.SQLite的相关类

  • SQLiteOpenHelper:抽象类,通过继承该类,重写数据库创建以及更新的方法, 我们还可以通过该类的对象获得数据库实例,或者关闭数据库
  • SQLiteDatabase:数据库访问类:通过该类的对象来对数据库做一些增删改查的操作
  • Cursor:游标,类似于JDBC里的resultset(结果集),可以简单理解为指向数据库中某一个记录的指针

三.优化格式

1.正常的数据库创建流程

首先基本上在进行android的SQLite的时候,基本上每次进行表格修改的时候都会进行一次数据库table的创建。

一般都是继承SQLiteOpenHelper 来实现数据库的表的创建,但是如果数据库的表每次都需要修改的话,每次都进行修改是否太麻烦了,而且如果你的项目中的依赖module太多,或者这个他是在maven当中,再找到他是不是很麻烦。


import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
 * Created by 先森 on 2017/9/21.
 */
  public static final String CREATE_BOOK = "CREATE TABLE book ("
            + "id  integer PRIMARY KEY Autoincrement ,"
            + "author text ,"
            + "price real ,"
            + "pages integer,"
            + "name text )";
    /**
     * integer:整形
     * real:浮点型
     * text:文本类型
     * blob:二进制类型
     * PRIMARY KEY将id列设置为主键
     * AutoIncrement关键字表示id列是自动增长的
     */

public class DatabaseHelper extends SQLiteOpenHelper {
    public DatabaseHelper(Context context, String name, int version) {
        super(context, name, null, version);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(CREATE_BOOK);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

2.配置一个ddl.sql数据库表和关键字的文件

所以我觉得不如就把他这个数据库表创建的sql语句放在一个资源文件当中相当于是一个配置文件了,这样配置字段什么的不仅看起来十分方便,而且十分方便去修改它。其次我们只要进行文件的读取,再转换成String格式不就可以了么

《《Android本地存储SQLite优化》》 数据库表创建的资源文件位置

下面把数据库创建的表sql语句如下,创建一个table1,版本号version :1

# ddl版本号
version=1

# 存储配置表
# 如果存在则删除表
drop table if exists table1;
create table table1(
    id varchar(200) not null, # 存储的key
    json text,                  # 存储的内容
    primary key(id)
)

3.对文件ddl读取

1.读取输入流把它变成String格式的文件
2.获取版本号
3.通过split来把Stringbuilder格式SQL语句变成String[]格式

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * Created by 张都 on 2017/9/20.
 */

public class DDLReader {
    private BufferedReader bufferedReader;
    private StringBuilder allsql;
    private int version;

    public DDLReader(InputStream in) {
        this.bufferedReader = new BufferedReader(new InputStreamReader(in));
        allsql=new StringBuilder();
        version=0;
    }

    public  void read(){
        try {
            while(bufferedReader.ready()){
                String line=bufferedReader.readLine();
                if(line==null){
                    break;
                }
                lineRead(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //数据库的每条读取
    private void lineRead(String line) {
        if(line.isEmpty())return;
        line=line.replaceAll("\\/\\*[\\S\\s]*?\\*\\/","").replaceAll("\\/\\/[\\S\\s]*$","").replaceAll("\\#[\\S\\s]*$","").trim();
        if(line.isEmpty())return;
        if(line.startsWith("version")){
            String[] versions=line.split("=");
            if(versions.length<2){
                throw new RuntimeException("ddl文件version设置错误 必须version=版本号为单独一行");
            }
            try {
                this.version=Integer.valueOf(versions[1].trim());
            }catch (Exception e){
                throw new RuntimeException("ddl文件version设置错误 version必须为正整数");
            }
            return;
        }
        allsql.append(line);
    }

    //获取当前数据库版本
    public int getVersion(){
        return version;
    }

    /**
     * 返回所有创建数据库的sql语句
     * @return
     */
    public String[] getAllddlsSql(){
        String[] ddl=allsql.toString().split(";");
        return ddl;
    }
}

定义一个接口对返回的数据的格式和种类进行

public interface IDao {
    /**
     * 查询
     * @param sql 查询语句
     * @return
     */
    List<HashMap<String,Object>> query(String sql);
    /**
     * 查询返回第几页的个数
     * @param sql 查询语句
     * @return
     */
    List<HashMap<String,Object>> query(String sql,int page,int pageSize);

    /**
     * 插入和更新操作
     * @param sql 查询语句
     * @return
     */
    int update(String sql);
    /**
     *获取本地数据库的数据个数
     * @param sql 查询语句
     * @return
     */
    int getCount(String sql);
}

实现接口进行具体方法的实现

public class Dao implements IDao {
    //数据库版本
    private  int version;
    //创建数据库的sql
    private String[] ddls;
    //获取数据库
    private SQLiteDatabase db;


    public Dao(Context context,String name) {
        getDDLs(context);
        this.db=new DataBaseHelper(context, name,version,ddls).getWritableDatabase();
    }

    private void getDDLs(Context context){
        try{
            InputStream in=context.getResources().openRawResource(R.raw.ddl);
            DDLReader ddlReader=new DDLReader(in);
            ddlReader.read();
            version=ddlReader.getVersion();
            ddls=ddlReader.getAllddlsSql();
        }catch (Exception e){
            throw new RuntimeException("ddl的version或者ddls没找到或者文件ddl没找到");
        }

    }

    @Override
    public List<HashMap<String, Object>> query(String sql) {
        if(db==null){
            return null;
        }else{
            Cursor cursor = db.rawQuery(sql, null);
            try {
                List<HashMap<String, Object>> list = new ArrayList();
                while (cursor.moveToNext()) {
                    HashMap<String, Object> map = new HashMap<String, Object>();
                    for (int i = 0; i < cursor.getColumnCount(); i++) {
                        Log.i(cursor.getColumnName(i), cursor.getString(i) == null ? "null" : cursor.getString(i));
                        map.put(cursor.getColumnName(i).toLowerCase(), cursor.getString(i));
                    }
                    list.add(map);
                }
                return list;
            }finally {
                cursor.close();
            }
        }
    }

    @Override
    public List<HashMap<String, Object>> query(String sql, int page, int pageSize) {
        int offset=(page-1)*pageSize;
        sql="select * from ("+sql+") a limit "+pageSize+" offset "+offset;
        return query(sql);
    }


    @Override
    public int update(String sql) {
        if(db==null){
            return -1;
        }else{
            try {
                db.execSQL(sql);
                return 1;
            }catch (Exception e){
                Log.e("appsql",sql);
                e.printStackTrace();
                return 0;
            }
        }
    }

    @Override
    public int getCount(String sql) {
        sql="select count(*) from ("+sql+") a";
        Cursor cursor = db.rawQuery(sql, null);
        try {
            cursor.moveToFirst();
            return cursor.getInt(0);
        }finally {
            cursor.close();
        }
    }
}

最后一步进行相关的输入参数的格式进行规定,提供一个公开的类CacheProvider
转换成json格式的话就需要进行json的依赖
在项目中添加如下fastjso的依赖

compile ‘com.alibaba:fastjson:1.1.52.android’

public class CacheProvider {

    private static IDao dao;

    public static void initDao(Context context, String name){
        dao=new Dao(context,name);
    }

    //插入数据和更新数据
    @Nullable
    public static void setString(String key,String data){
        int size = dao.getCount("select * from storage where id='" + key + "'");
        String value=String.valueOf(data).replaceAll("'","\\'");
        if (size == 0) {
            dao.update("insert into storage values('" + key + "','" + value + "')");
        } else {
            int s = dao.update("update storage set json='" + value  + "' where id='" + key + "'");
        }
    }

    @Nullable
    public static void setObject(String key,Object data){
        setString(key, JSON.toJSONString(data));
    }

    @Nullable
    public static void setDouble(String key,double v){
        setObject(key,v);
    }

    @Nullable
    public static void setObjects(String key,List<? extends Object> list){
        setString(key, JSON.toJSONString(list));
    }



    @Nullable
    public static String getString(String key){
        List<HashMap<String, Object>> list = dao.query("select * from storage where id='" + key + "'");
        if (list.isEmpty()) {
            return null;
        } else {
            return list.get(0).get("json").toString();
        }
    }

    /**
     * 获取存储的boolean值
     * @param key
     * @return
     */
    @Nullable
    public static boolean getBoolean(String key){
        return Boolean.valueOf(getString(key));
    }

    @Nullable
    public static int getInteger(String key){
        try {
            return Integer.valueOf(getString(key));
        }catch (Exception e){
            return 0;
        }
    }

    @Nullable
    public static double getDouble(String key){
        try {
            return Double.valueOf(getString(key));
        }catch (Exception e){
            return -1;
        }
    }

    @Nullable
    public static <T>T getObject(String key, Class<T> clazz){
        String json=getString(key);
        if(json==null){
            return null;
        }
        return JSON.parseObject(json,clazz);
    }

    @NonNull
    public static <T>List<T> getObjects(String key, Class<T> clazz){
        String json=getString(key);
        if(json==null){
            return new ArrayList<>();
        }
        return JSON.parseArray(json,clazz);
    }
}

    原文作者:Charon_Pluto
    原文地址: https://www.jianshu.com/p/729124e626fc
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞