Android 数据库框架设计

数据库的作用:

在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 map = Collections.synchronizedMap(new HashMap());

    protected BaseDaoFactory(){

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

        sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(sqlitePath,null);

    }

    // 生产basedao对象

    public ,M> T getBaseDao(Class daoClass,Class 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 implements IBaseDao{

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

    private SQLiteDatabase sqLiteDatabase;

    // 表名

    private String tableName;

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

    private Class entityClass;

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

    private boolean isInit = false;

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

    private HashMap cacheMap;

    public boolean init(SQLiteDatabase sqLiteDatabase,Class 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 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 query(T where) {

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

    }

    @Override

    public List 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 result = getResult(cursor,where);

        return result;

    }

    private List 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 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 map) {

        ContentValues contentValues = new ContentValues();

        Set keys = map.keySet();

        Iterator 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 getValues(T entity) {

        HashMap map = new HashMap<>();

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

        Iterator 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 数据库框架设计)