千家信息网

Android架构中的数据库框架该如何搭建

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章将为大家详细讲解有关Android架构中的数据库框架该如何搭建,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。前言:你还在苦恼的写SQL么?你还
千家信息网最后更新 2026年11月03日Android架构中的数据库框架该如何搭建

这篇文章将为大家详细讲解有关Android架构中的数据库框架该如何搭建,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

    前言:

    你还在苦恼的写SQL么?你还在为数据库升级而烦恼么?你还在因查询数据而写繁琐不可用的代码么? 在这,这些都将不复存在!在本篇中,将会让你一点一滴从无到有创建一个不再为数据库而烦恼的框架。

    在开始之前我们先欣赏一下本章实现的最终效果 效果展示

    如图所示:

    • 对应的model,可直接成为表结构,不再写对应的 Create table xxx对应的SQL了

    • 对应model的Dao层,里面封装了数据表的基本操作(增删改查)

    • 对应的增删改查操作,再也不用SQL了,全用对象处理

    接下来开始实战了

    1、先创建对应相关操作的注解

    1.1 bTable 标识表

    @Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface DbTable { //表名    String value();}

    1.2 DbPrimaryKey 标识主键

    @Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface DbPrimaryKey {        //表列名    String value();    //是否为自动增长    boolean isAuto() default false;}

    1.3 DbFiled 标识成员属性

    @Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface DbFiled {  //表列名    String value();    /* 这里可以像主键一样,添加其他属性,比如是否唯一约束,是否非空等 甚至可以将主键的约束放在这里来,只是表明可以这样做,具体怎样扩展,完全可以按你们想法来 */}

    2、创建对应表操作类Dao层

    2.1 建 待实现的基层 IBaseDao

    public interface IBaseDao {    Long insert(T entity);    int update(T entity, T where);    /**     * 删除数据     *     * @param where     * @return     */    int delete(T where);    /**     * 查询数据     */    List query(T where);    List query(T where, String groupBy, String orderBy, String having, Integer startIndex,                  Integer limit);}

    代码分析:

    这里创建了基类 IBaseDao ,拥有待实现的增删改查, T 代表对应的 数据表结构的 model。

    2.2 建已实现的基层 BaseDao

    public class BaseDao implements IBaseDao {    private static final String TAG = "hqk";    /**     * 持有数据库操作类的引用     */    private SQLiteDatabase database;    /**     * 持有操作数据库表所对应的java类型     * User     */    private Class entityClass;    /**     * 保证实例化一次     */    private boolean isInit = false;    private String tableName;    //    检查表    private HashMap cacheMap;    protected BaseDao() {    }    protected synchronized boolean init(Class entity, SQLiteDatabase sqLiteDatabase) {        if (!isInit) {            //初始化完了  自动建表            entityClass = entity;            database = sqLiteDatabase;            if (entity.getAnnotation(DbTable.class) == null) {                tableName = entity.getClass().getSimpleName();            } else {                tableName = entity.getAnnotation(DbTable.class).value();            }            if (!database.isOpen()) {                return false;            }            String sql = createTable();            database.execSQL(sql);            //建立好映射关系            initCacheMap();            isInit = true;        }        return true;    }    /**     * 将真实表中的列名  + 成员变量进行 映射     * 缓存对应的 表 Model里的属性名以及对应表列名     */    private void initCacheMap() {        cacheMap = new HashMap<>();        //这里没有必要查询 对应表中的任何数据,只想要对应表列名,所以 这 limit 0        String sql = "select * from " + tableName + " limit 0";        Cursor cursor = database.rawQuery(sql, null);        String[] columnNames = cursor.getColumnNames();        Field[] columnFields = entityClass.getDeclaredFields();        //获取对应表中的列名数组,以及对应表Model里面的属性数组        for (String columnName : columnNames) {            Field resultField = null;            for (Field field : columnFields) {                //拿到对应属性的注解值                String fieldAnnotationName = field.getAnnotation(DbFiled.class).value();                //如果对应的属性注解值与数据库表列名相同,则拿到对应属性值                if (columnName.equals(fieldAnnotationName)) {                    resultField = field;                    break;                }            }            if (resultField != null) {                cacheMap.put(columnName, resultField);            }        }    }    /**     * 组装 创建表的SQL语句     *     * @return     */    private String createTable() {        StringBuffer stringBuffer = new StringBuffer();        //开始组装 SQL语句        stringBuffer.append("create table if not exists ");        stringBuffer.append(tableName + " (");        Field[] fields = entityClass.getDeclaredFields();        for (Field field : fields) {            Class type = field.getType();            String primaryKey = null;            try {                primaryKey = field.getAnnotation(DbPrimaryKey.class).value();            } catch (Exception e) {            }            Log.i(TAG, "createTable primaryKey " + primaryKey);            Log.i(TAG, "createTable type " + type);            if (type == String.class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " TEXT,");                } else {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + " TEXT PRIMARY KEY,");                }            } else if (type == Double.class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  DOUBLE,");                } else {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  DOUBLE PRIMARY KEY,");                }            } else if (type == Integer.class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  INTEGER,");                } else {                    boolean isAuto = field.getAnnotation(DbPrimaryKey.class).isAuto();                    if (isAuto) {                        stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  INTEGER PRIMARY KEY AUTOINCREMENT,");                    } else {                        stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  INTEGER PRIMARY KEY,");                    }                }            } else if (type == Long.class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  BIGINT,");                } else {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  BIGINT PRIMARY KEY,");                }            } else if (type == byte[].class) {                if (null == primaryKey) {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  BLOB,");                } else {                    stringBuffer.append(field.getAnnotation(DbFiled.class).value() + "  BLOB PRIMARY KEY,");                }            } else {                  /*                不支持的类型                 */                continue;            }        }        //循环完成后,最后一项会有 逗号 ,如果最后一个是逗号,则删除最后一个字符        if (stringBuffer.charAt(stringBuffer.length() - 1) == ',') {            stringBuffer.deleteCharAt(stringBuffer.length() - 1);        }        //SQL 语句 收尾        stringBuffer.append(")");        Log.i(TAG, "createTable: " + stringBuffer.toString());        return stringBuffer.toString();    }    @Override    public Long insert(T entity) {        Map map = getValues(entity);        ContentValues contentValues = getContentValues(map);        return database.insert(tableName, null, contentValues);    }    /**     * 获取对应 model 属性以及对应的注解值(表列名值)     *     * @param entity 对应 表结构的model     * @return 返回 key= 列名,value=属性的值          map集合     */    private Map getValues(T entity) {        HashMap map = new HashMap<>();        //获取对应缓存 model 里面的属性键        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 = field.getAnnotation(DbFiled.class).value();                //遍历 取出对应 属性的值 以及对应的 注解值,并添加至Map里                if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {                    map.put(key, value);                }            } catch (IllegalAccessException e) {                e.printStackTrace();            }        }        return map;    }    /**     * 数据库数据结构的封装     *     * @param map 带有 以表列名为键,的map     * @return 数据库需要的封装格式     */    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;    }    @Override    public int update(T entity, T where) {        Map values = getValues(entity);        ContentValues contentValues = getContentValues(values);        //条件        Map whereMap = getValues(where);        Condition condition = new Condition(whereMap);        return database.update(tableName, contentValues, condition.whereClause, condition.whereArgs);    }    class Condition {        String whereClause;        String[] whereArgs;        public Condition(Map whereClause) {            boolean flag = false;            if (true && flag) {            }            ArrayList list = new ArrayList();            StringBuilder stringBuilder = new StringBuilder();            // 这里之所以先添加 1=1 这个条件 是因为            // SQL  where  后面需要给条件判断,而下面 while 循环 直接添加了 and            // SQL 语句就变成了 where and  这显然不符合SQL语句            // 因此 加上 1=1 就变成了  where 1=1 and xx。起了一个呈上去下的作用            stringBuilder.append("1=1");            Set keys = whereClause.keySet();            Iterator iterator = keys.iterator();            while (iterator.hasNext()) {                String key = (String) iterator.next();                String value = whereClause.get(key);                if (value != null) {                    stringBuilder.append(" and " + key + " =?");                    list.add(value);                }            }            this.whereClause = stringBuilder.toString();            this.whereArgs = (String[]) list.toArray(new String[list.size()]);        }    }    @Override    public int delete(T where) {        Map map = getValues(where);        Condition condition = new Condition(map);        return database.delete(tableName, condition.whereClause, condition.whereArgs);    }    @Override    public List query(T where) {        return query(where, null, null, null, null, null        );    }    //所有  条件    @Override    public List query(T where, String groupBy, String orderBy, String having,Integer startIndex,                         Integer limit) {        String limitString=null;        if(startIndex!=null&&limit!=null)        {            limitString=startIndex+" , "+limit;        }        Map map=getValues(where);        Condition condition=new Condition(map);        Cursor cursor=  database.query(tableName, null, condition.whereClause,                condition.whereArgs,                groupBy, having,                orderBy, limitString        );//        封装   --返回        List result = getResult(cursor, where);        cursor.close();        return result;    }    private List getResult(Cursor cursor, T where) {        ArrayList  list=new ArrayList();        Object item;        while (cursor.moveToNext()) {            try {//                cachmap        ---对象中的成员变量    Filed    annotion-- tb_name//cacheMap    name  ---Filed       1//            tb_name       ---Filed  2                item=where.getClass().newInstance();                Iterator iterator=cacheMap.entrySet().iterator();                while (iterator.hasNext())                {                    Map.Entry entry= (Map.Entry) iterator.next();                    //tb_name                    /**                     * 得到列名                     */                    String colomunName= (String) entry.getKey();//                    通过列名查找到游标的索性                    Integer colmunIndex= cursor.getColumnIndex(colomunName);//                    Filed//反射的成员 cursor                    Field field= (Field) entry.getValue();                    Class type=field.getType();                    if(colmunIndex!=-1)                    {//                        if (type == String.class) {                            field.set(item, cursor.getString(colmunIndex));                        }else if(type==Double.class)                        {                            field.set(item,cursor.getDouble(colmunIndex));                        }else  if(type==Integer.class)                        {                            field.set(item,cursor.getInt(colmunIndex));                        }else if(type==Long.class)                        {                            field.set(item,cursor.getLong(colmunIndex));                        }else  if(type==byte[].class)                        {                            field.set(item,cursor.getBlob(colmunIndex));                            /*                            不支持的类型                             */                        }else {                            continue;                        }                    }                }                list.add(item);            } catch ( Exception e) {                e.printStackTrace();            }        }        return list;    }}

    代码分析:

    在这个BaseDao 里面,几乎分担了数据表大部分的脏活累活,根据model结构自动生成对应SQL并创建对应表,以及基础的增删改查操作。

    2.3 建对应model 的Dao层

    1.UserDao

    public class UserDao extends BaseDao {    @Override    public Long insert(User entity) {        return super.insert(entity);    }    @Override    public List query(User where) {        return super.query(where);    }    @Override    public int delete(User where) {        return super.delete(where);    }    @Override    public int update(User entity, User where) {        return super.update(entity, where);    }    @Override    public List query(User where, String groupBy, String orderBy, String having, Integer startIndex, Integer limit) {        return super.query(where, groupBy, orderBy, having, startIndex, limit);    }}

    2.PhotoDao

    public class PhotoDao extends BaseDao {    @Override    public Long insert(Photo entity) {        return super.insert(entity);    }    @Override    public int update(Photo entity, Photo where) {        return super.update(entity, where);    }    @Override    public List query(Photo where) {        return super.query(where);    }    @Override    public int delete(Photo where) {        return super.delete(where);    }}

    代码分析:

    虽然 BaseDao 已经完成了几乎所有的操作,但是一旦遇到多表查询的时候,光是一个BaseDao远远不够。所以这里还是选择创建不同model的Dao层,并继承与BaseDao。也就是说,有多少表,最好就创建对应多少个Dao层。

    3、创建数据库工厂

    public class BaseDaoFactory {    private final String TAG = "hqk";    private SQLiteDatabase sqLiteDatabase;    private String sqliteDatabasePath;    private static BaseDaoFactory instance = new BaseDaoFactory();    //饿汉单例模式    public static BaseDaoFactory getInstance() {        return instance;    }    public BaseDaoFactory() {        //读者可随意更改路径以及对应数据库名,这里演示暂时放在根目录        sqliteDatabasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/hqk.db";        sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(sqliteDatabasePath, null);        Log.i(TAG, "sqliteDatabasePath : " + sqliteDatabasePath);        Log.i(TAG, "sqLiteDatabase : " + sqLiteDatabase.getPath());    }    /**     * @param clazz     * @param entityClass     * @param          我们在这可以把它看成某一个对象,它继承与 BaseDao ,而里面的T 就是下面的那个空对象     * @param          我们在这可以吧它看成某一个空对象 T     * @return     */    public synchronized , T> R createBaseDao(Class clazz, Class entityClass) {        BaseDao baseDao = null;        try {            baseDao = clazz.newInstance();            baseDao.init(entityClass, sqLiteDatabase);        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        }        return (R) baseDao;    }}

    代码分析:

    这里也没啥好分析的,就一个数据库创建,以及对应model的初始化。唯一值得注意的就是初始化的时候用了俩个泛型,具体什么意思,可按照代码注释理解。

    4、创建对应model

    1.User

    @DbTable("tb_user")public class User {        @DbPrimaryKey(value = "tb_id", isAuto = true)    @DbFiled("tb_id")    public Integer id;    @DbFiled("tb_name")    public String name;//        @DbFiled("tb_age")    public Integer age;    public User(String name, Integer age) {        this.name = name;        this.age = age;    }    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 Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    public User() {    }}

    2.Photo

    @DbTable("tb_photo")public class Photo {    @DbFiled("time")    private  String time;    @DbFiled("id")    private  Long id;    @DbFiled("path")    private  String path;    public Photo( ) {    }    public Photo(String time, Long id, String path) {        this.time = time;        this.id = id;        this.path = path;    }    public void setTime(String time) {        this.time = time;    }    public void setId(Long id) {        this.id = id;    }    public void setPath(String path) {        this.path = path;    }}

    代码分析:

    这俩类就是对应表结构model 类,用到了对应注解,相信通过注解能够清楚知道对应表结构是怎样的。

    5、最终使用

    ainActivity

    public class MainActivity extends AppCompatActivity {    UserDao userDao;    PhotoDao photoDao;    private ArrayList listUser = new ArrayList<>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        requestPermission(this);    }    public void save(View view) {        User user = new User("hqk", 18);        long size = userDao.insert(user);        Photo photo = new Photo("time", System.currentTimeMillis(), "path");        long photoSize = photoDao.insert(photo);        Toast.makeText(this, "save line :   " + size, Toast.LENGTH_LONG).show();    }    public void update(View view) {        User where = new User();        where.setAge(18);        int size = userDao.update(new User("TOM", 99), where);        Toast.makeText(this, "update Size :   " + size, Toast.LENGTH_LONG).show();    }    public void delete(View view) {        User where = new User();        where.setAge(18);        int size = userDao.delete(where);        Toast.makeText(this, "delete Size :   " + size, Toast.LENGTH_LONG).show();    }    public void queryList(View view) {        listUser.clear();        listUser.addAll(userDao.query(new User()));        Toast.makeText(this, "查询条数为:" + listUser.size(), Toast.LENGTH_LONG).show();    }    public void requestPermission(            Activity activity) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ActivityCompat.checkSelfPermission(activity,                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {            ActivityCompat.requestPermissions(activity, new String[]{                    Manifest.permission.READ_EXTERNAL_STORAGE,                    Manifest.permission.WRITE_EXTERNAL_STORAGE            }, 1);            return;        }        createTable();    }    private void createTable() {        userDao = BaseDaoFactory.getInstance().createBaseDao(UserDao.class, User.class);        photoDao = BaseDaoFactory.getInstance().createBaseDao(PhotoDao.class, Photo.class);    }    @Override    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        createTable();    }}

    关于Android架构中的数据库框架该如何搭建就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

    数据 数据库 属性 代码 注解 结构 分析 对象 语句 查询 成员 条件 封装 框架 就是 数据表 标识 类型 架构 烦恼 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网与科技 科技赋能下的互联网金融 互联网金融监管科技数据 互联网科技公司税收优惠 互联网的科技创新 互联网金融 金融科技 嘟嘟瓜互联网科技 深圳齐家互联网科技 互联网科技公司有哪些 科技大学互联网专业好不好 广州优美互联网科技 中国的互联网科技企业的崛起 玉溪互联网科技怎么选 互联网科技创新的路径 互联网安防科技感 互联网科技职业技能培训学校 安徽零酒互联网科技有限公司 杭州科技互联网公司有哪些 互联网科技自媒体灵感 如何强化互联网金融科技 期待互联网科技 全球顶尖互联网科技公司 南平创想时代互联网科技有限公司 消费医药和互联网科技 浙南科技城互联网大厦建设工程 恒生互联网科技业指数调整周期 广州百诚互联网科技有限公司官网 广州有谷有贝互联网科技有限公司 云南互联网科技学费 六子台科技互联网展会
    0