美文网首页
Android 数据库框架设计

Android 数据库框架设计

作者: 佼佼者Mr | 来源:发表于2020-02-15 22:22 被阅读0次

    数据库的作用:

    在Android开发中,数据库在小中型的app中使用并不广泛,但对于数据管理的方便性是其他数据存储结构工具无法取代的,特点:数据集中管理,控制冗余,提高数据的利用率和一致性,有利于程序的开发和维护。

    数据库的设计:

    数据库设计的三大范式:

    第一范式:原子性

    第二范式:唯一性

    第三范式:避免冗余性

    Android数据库架构分析

    如何自动创建数据库、自动创建数据库表

    通过创建自定义注解,将表名应用为类名,数据库字段设为类的全局变量,创建bean对象,运用反射得到类名和字段,创建sql语句,自动创建数据可

    // 得到User对应表名

    @DbTable("tb_user")

    public class User {

        // 得到User对象对应列名

        @DbField("u_id")

        private Integer id;

        private String name;

        private String password;

        private Integer status;

        public Integer getStatus() {

            return status;

        }

        public void setStatus(Integer status) {

            this.status = status;

        }

        public User(){}

        public User(Integer id, String name, String password) {

            this.id = id;

            this.name = name;

            this.password = password;

        }

        public Integer getId() {

            return id;

        }

        public void setId(Integer id) {

            this.id = id;

        }

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public String getPassword() {

            return password;

        }

        public void setPassword(String password) {

            this.password = password;

        }

        @Override

        public String toString() {

            return "User{" +

                    "id=" + id +

                    ", name='" + name + '\'' +

                    ", password='" + password + '\'' +

                    '}';

        }

    }

    创建db

    public class BaseDaoFactory {

        private static final BaseDaoFactory instance = new BaseDaoFactory();

        public static BaseDaoFactory getInstance(){

            return instance;

        }

        private SQLiteDatabase sqLiteDatabase;

        private String sqlitePath;

        // 设计要给数据库连接池,new 容器,只要new个一次,下次就不会再创建了。考虑多线程的问题

        protected Map<String,BaseDao> map = Collections.synchronizedMap(new HashMap<String, BaseDao>());

        protected BaseDaoFactory(){

            sqlitePath = "data/data/com.neteasedb/ne.db";

            sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(sqlitePath,null);

        }

        // 生产basedao对象

        public <T extends BaseDao<M>,M> T getBaseDao(Class<T> daoClass,Class<M> entityClass){

            BaseDao baseDao = null;

            if(map.get(daoClass.getSimpleName()) != null){

                return (T)map.get(daoClass.getSimpleName());

            }

            try {

                baseDao = daoClass.newInstance();

                baseDao.init(sqLiteDatabase,entityClass);

                map.put(daoClass.getSimpleName(),baseDao);

            } catch (IllegalAccessException e) {

                e.printStackTrace();

            } catch (InstantiationException e) {

                e.printStackTrace();

            }

            return (T)baseDao;

        }

    }

    如何让用户在使用的时候非常的方便、 数据库的查询,修改,删除

    创建SQLiteDatabase持有数据库的引用,创建一个缓存空间,避免频繁引用反射,耗费内存。

    public class BaseDao<T> implements IBaseDao<T>{

        // 持有数据库操作的引用

        private SQLiteDatabase sqLiteDatabase;

        // 表名

        private String tableName;

        // 操作数据库所对应的java类型

        private Class<T> entityClass;

        // 标识,用来标识是否已经做过初始化

        private boolean isInit = false;

        // 定义一个缓存空间(key 字段名 value 成员变量)

        private HashMap<String,Field> cacheMap;

        public boolean init(SQLiteDatabase sqLiteDatabase,Class<T> entityClass){

            this.sqLiteDatabase = sqLiteDatabase;

            this.entityClass = entityClass;

            if(!isInit){

                // 根据传入的Class进行数据表的创建 本例子中对应的是User对象;

                DbTable dt = entityClass.getAnnotation(DbTable.class);

                if(dt != null && !"".equals(dt.value())){

                    tableName = dt.value();

                }else{

                    tableName = entityClass.getName();

                }

                if(!sqLiteDatabase.isOpen()){

                    return false;

                }

                String createTableSql = getCreateTableSql();

                sqLiteDatabase.execSQL(createTableSql);

                cacheMap = new HashMap<>();

                initCacheMap();

                isInit = true;

            }

            return isInit;

        }

        private void initCacheMap() {

            // 取得所有的列名

            String sql = "select * from "+tableName+" limit 1,0";

            Cursor cursor = sqLiteDatabase.rawQuery(sql,null);

            String[] columnNames = cursor.getColumnNames();

            // 获取所有的成员变量

            Field[] colunmnFields = entityClass.getDeclaredFields();

            // 将字段访问权限打开

            for(Field field : colunmnFields){

                field.setAccessible(true);

            }

            for(String columnName:columnNames){

                Field columnField=null;

                for(Field field:colunmnFields){

                    String fieldName=null;

                    if(field.getAnnotation(DbField.class)!=null){

                        fieldName=field.getAnnotation(DbField.class).value();

                    }else{

                        fieldName=field.getName();

                    }

                    if(columnName.equals(fieldName)){

                        columnField=field;

                        break;

                    }

                }

                if(columnField!=null){

                    cacheMap.put(columnName,columnField);

                }

            }

        }

        private String getCreateTableSql() {

            StringBuilder stringBuilder = new StringBuilder();

            stringBuilder.append("create table if not exists ");

            stringBuilder.append(tableName+"(");

            // 反射得到所有的成员变量

            Field[] fields = entityClass.getDeclaredFields();

            for(Field field : fields){

                Class type = field.getType();

                DbField dbField = field.getAnnotation(DbField.class);

                if(dbField != null && !"".equals(dbField.value())){

                    if(type == String.class){

                        stringBuilder.append(dbField.value()+" TEXT,");

                    }else if(type== Integer.class){

                        stringBuilder.append(dbField.value()+" INTEGER,");

                    }else if(type== Long.class){

                        stringBuilder.append(dbField.value()+" BIGINT,");

                    }else if(type== Double.class){

                        stringBuilder.append(dbField.value()+" DOUBLE,");

                    }else if(type==byte[].class){

                        stringBuilder.append(dbField.value()+" BLOB,");

                    }else{

                        //不支持的类型号

                        continue;

                    }

                }else{

                    if(type== String.class){

                        stringBuilder.append(field.getName()+" TEXT,");

                    }else if(type== Integer.class){

                        stringBuilder.append(field.getName()+" INTEGER,");

                    }else if(type== Long.class){

                        stringBuilder.append(field.getName()+" BIGINT,");

                    }else if(type== Double.class){

                        stringBuilder.append(field.getName()+" DOUBLE,");

                    }else if(type==byte[].class){

                        stringBuilder.append(field.getName()+" BLOB,");

                    }else{

                        //不支持的类型号

                        continue;

                    }

                }

            }

            if(stringBuilder.charAt(stringBuilder.length()-1)==','){

                stringBuilder.deleteCharAt(stringBuilder.length()-1);

            }

            stringBuilder.append(")");

            return stringBuilder.toString();

        }

        @Override

        public long insert(T entity) {

            // user 对象 转换为contentvalues  new User(id 1,name = "netease","password");

            Map<String,String> map = getValues(entity);

            ContentValues values = getContentValues(map);

            return sqLiteDatabase.insert(tableName,null,values);

        }

        @Override

        public long update(T entity, T where) {

            // 将传进来的对象 将成员变量和成员变量的值 转为map

            Map map = getValues(entity);

            ContentValues values = getContentValues(map);

            Map whereMap = getValues(where);

            Condition condition = new Condition(whereMap);

            return sqLiteDatabase.update( tableName,values,condition.whereCause,condition.whereArgs);

        }

        @Override

        public int delete(T where) {

            Map map = getValues(where);

            Condition condition = new Condition(map);

            return sqLiteDatabase.delete(tableName,condition.whereCause,condition.whereArgs);

        }

        @Override

        public List<T> query(T where) {

            return query(where,null,null,null);

        }

        @Override

        public List<T> query(T where, String orderBy, Integer startIndex, Integer limit) {

            Map map = getValues(where);

            // select * from tableName  limit 0,10;

            String limitString = null;

            if(startIndex != null && limit != null){

                limitString = startIndex+" , "+limit;

            }

    //        String seclections = "where 1=1 and id=? and name=?";

    //        String selectionArgs = String[]{,""};

            // select * from tableName where id=? and name=?

            Condition condition = new Condition(map);

            Cursor cursor = sqLiteDatabase.query(tableName,null,condition.whereCause,condition.whereArgs,null,null,

                    orderBy,limitString);

            // 定义一个解析游标的方法

            List<T> result = getResult(cursor,where);

            return result;

        }

        private List<T> getResult(Cursor cursor, T obj) {

            ArrayList list = new ArrayList();

            Object item = null;// User user = null;

            while (cursor.moveToNext()){

                try {

                    item = obj.getClass().newInstance(); // user = new User(); user.setId(cursor.getId);

                    Iterator iterator = cacheMap.entrySet().iterator();// 成员变量

                    while (iterator.hasNext()){

                        Map.Entry entry = (Map.Entry)iterator.next();

                        // 获取列名

                        String columnName = (String)entry.getKey();

                        // 以列名拿到列名在游标中的位置

                        Integer columnIndex = cursor.getColumnIndex(columnName);

                        // 获取成员变量的类型

                        Field field = (Field) entry.getValue();

                        Class type = field.getType();

                        // cursor.getString(columnIndex);

                        if(columnIndex != -1){

                            if(type == String.class){

                                // User user = new User

                                // user.setId(1);  id.set(user,1);

                                field.set(item,cursor.getString(columnIndex));

                            }else if(type== Double.class){

                                field.set(item,cursor.getDouble(columnIndex));

                            }else if(type== Integer.class){

                                field.set(item,cursor.getInt(columnIndex));

                            }else if(type== Long.class){

                                field.set(item,cursor.getLong(columnIndex));

                            }else if(type==byte[].class){

                                field.set(item,cursor.getBlob(columnIndex));

                            }else{

                                continue;

                            }

                        }

                    }

                    list.add(item);

                } catch (IllegalAccessException e) {

                    e.printStackTrace();

                } catch (InstantiationException e) {

                    e.printStackTrace();

                }

            }

            cursor.close();

            return list;

        }

        private class Condition{

            private String whereCause;

            private String[] whereArgs;

            public Condition(Map<String,String> whereMap){

                ArrayList list = new ArrayList();

                StringBuilder stringBuilder = new StringBuilder();

                stringBuilder.append("1=1");

                // 获取所有的字段名

                Set keys = whereMap.keySet();

                Iterator iterator = keys.iterator();

                while (iterator.hasNext()){

                    String key = (String)iterator.next();

                    String value = whereMap.get(key);

                    if(value != null){

                        stringBuilder.append(" and "+key+" =?");

                        list.add(value);

                    }

                }

                this.whereCause = stringBuilder.toString();

                this.whereArgs = (String[])list.toArray(new String[list.size()]);

            }

        }

        private ContentValues getContentValues(Map<String, String> map) {

            ContentValues contentValues = new ContentValues();

            Set keys = map.keySet();

            Iterator<String> iterator = keys.iterator();

            while (iterator.hasNext()){

                String key = iterator.next();

                String value = map.get(key);

                if(value != null){

                    contentValues.put(key,value);

                }

            }

            return contentValues;

        }

        private Map<String, String> getValues(T entity) {

            HashMap<String,String> map = new HashMap<>();

            // 得到所有的成员变量,user的成员变量

            Iterator<Field> fieldIterator = cacheMap.values().iterator();

            while (fieldIterator.hasNext()){

                Field field = fieldIterator.next();

                field.setAccessible(true);

                // 获取成员变量的值

                try {

                    Object object = field.get(entity);

                    if(object == null){

                        continue;

                    }

                    String value = object.toString();

                    // 获取列名

                    String key = null;

                    DbField dbField = field.getAnnotation(DbField.class);

                    if( dbField != null && !"".equals(dbField.value())){

                        key = dbField.value();

                    }else{

                        key = field.getName();

                    }

                    if(!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)){

                        map.put(key,value);

                    }

                } catch (IllegalAccessException e) {

                    e.printStackTrace();

                }

            }

            return map;

        }

    }

    数据库分库

    应用场景:大型app中,当有多个账号需要切换时。

    有点:数据隔离,互不打扰。便于数据的管理。

    缺点:会消耗内存,不过相比于有点,这点内存还是可以接受的

    数据库的升级

    原理 利用xml文件进行升级 

    步骤 

    1.先把数据备份,重命名保存在当前位置,防止数据丢失,以便升级后将数据重新加入到升级后的表中

    2.重新创建数据库表

    3.将重命名之后的表里的数据导入到新建的表里

    4.将之前备份的表删除

    5.利用xml升级必须知道之前的表结构和了解xml,所以只能针对自己的项目进行升级

    相关文章

      网友评论

          本文标题:Android 数据库框架设计

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