《Android本地存储SQLite优化》

作者: Charon_Pluto | 来源:发表于2017-09-21 16:28 被阅读239次

    一.简介

    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格式不就可以了么

    数据库表创建的资源文件位置

    下面把数据库创建的表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);
        }
    }
    
    

    相关文章

      网友评论

        本文标题:《Android本地存储SQLite优化》

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