移动架构29_面向对象式手写数据库架构设计一(基本框架与插入数据)

本文介绍了一个自定义的Android数据库框架,该框架支持自定义数据库位置,并通过反射和注解简化了表结构定义与数据操作。文章详细展示了如何设计并实现这一框架,包括核心组件如BaseDao、工厂类BaseDaoFactory等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android移动架构汇总​​​​​​​
Demo地址:
https://gitee.com/YuBaoZi/codes/nujo5r0xsvdyte9pq7lha77
建议:代码很简单,建议敲两遍就能理解了,很实用;

效果:
这里写图片描述
数据库查看工具:SqliteLookup

##一、需求:
####设计一个数据库框架,数据库的位置自定义,数据库中每张表的创建和表插入、修改数据逻辑要求能够统一

##二、原理分析:
####1、不用DataBaseOpenHelper,而用SQLiteDatabase.openOrCreateDatabase来创建数据库,指定一个数据库的位置
####2、每张表对应一个业务Bean,插入数据就是插入一个业务Bean;
####3、提供数据库操作类的工厂类,根据传入的类型,生成对应的数据库操作类,完成数据库的初始化;
####4、定义一个数据库操作接口:定义插入,修改的数据的行为;
####定义一个抽象类(表操作类)实现这个接口:封装所有具体操作数据类的同一行为
#####(1)一个抽象的创建表的方法(因为不同表的创建具体实现不同);
#####(2)根据业务Bean生成一个表中列名和Bean的方法名对应的集合,由于实际中成员名和列名可能不同,通过注解实现“翻译;
#####(3)解析业务Bean,将业务Bean中的成员名和(2)中的集合比对,生成一个列名对应Bean的value的集合
#####(4)将(3)中的集合转换成数据库识别的内容(contentValue),设置到数据库中去

5、具体业务中:不同的业务逻辑对应一个业务Bean(用注解解释),和一个表具体操作类(实现抽象的表操作类,定义具体的表创建方法)

技术点:SQLiteDatabase、反射、泛型、注解、数据库语句拼接、模板设计模式、工厂设计模式、单例模式
工厂类:接受泛型,产生对应的数据库操作类
-> 接口:封装插入、修改的行为、限制类型;
-> 数据库抽象操作类:解析传入的业务Bean,生成可以直接进行数据库操作的API;定义操作类的类型
-> 具体操作类:实现具体不同表的创建
-> Bean:表的表名、列名封装;方便具体的业务操作;
这里写图片描述

这里写图片描述
#三、代码
###1、定义表名和列名对应的注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DbTable {
    String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DbFiled {
    String value();
}

###2、插入

public interface IBaseDao<T> {
//插入数据
    Long insert(T entity);
    Long update(T entity,T where);
}

3、封装解析业务Bean(也就是T类型)的抽象类

public abstract class BaseDao<T> implements  IBaseDao<T> {
    /**]
     * 持有数据库操作类的引用
     */
    private SQLiteDatabase database;
    /**
     * 保证实例化一次
     */
    private boolean isInit=false;
    /**
     * 持有操作数据库表所对应的java类型
     * User
     */
    private Class<T> entityClass;
    /**
     * 维护这表名与成员变量名的映射关系
     * key---》表名
     * value --》Field
     */
    private HashMap<String,Field> cacheMap;

    private String tableName;
    /**
     * @param entity
     * @param sqLiteDatabase
     * @return
     * 实例化一次
     */
    protected synchronized boolean init(Class<T> 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;
              }
                if(!TextUtils.isEmpty(createTable()))
                {
                    database.execSQL(createTable());
                }
              cacheMap=new HashMap<>();
              initCacheMap();

            isInit=true;
        }
        return  isInit;
    }

    /**
     * 维护映射关系
     */
    private void initCacheMap() {
        String sql="select * from "+this.tableName+" limit 1 , 0";
        Cursor cursor=null;
        try {
            cursor=database.rawQuery(sql,null);
            /**
             * 表的列名数组
             */
            String[] columnNames=cursor.getColumnNames();
            /**
             * 拿到Filed数组
             */
            Field[] colmunFields=entityClass.getFields();
            for(Field filed:colmunFields)
            {
                 filed.setAccessible(true);
            }
            /**
             * 开始找对应关系
             */
            for(String colmunName:columnNames)
            {
                /**
                 * 如果找到对应的Filed就赋值给他
                 * User
                 */
                 Field colmunFiled=null;
                for (Field field:colmunFields)
                {
                    String fieldName=null;
                    if(field.getAnnotation(DbFiled.class)!=null)
                    {
                         fieldName=field.getAnnotation(DbFiled.class).value();
                    }else
                    {
                        fieldName =field.getName();
                    }
                    /**
                     * 如果表的列名 等于了  成员变量的注解名字
                     */
                    if(colmunName.equals(fieldName))
                    {
                        colmunFiled= field;
                        break;
                    }
                }
                //找到了对应关系
                if(colmunFiled!=null)
                {
                    cacheMap.put(colmunName,colmunFiled);
                }
            }

        }catch (Exception e)
        {

        }finally {
            cursor.close();
        }

    }

    @Override
    public Long insert(T entity) {
        Map<String,String> map=getValues(entity);
        ContentValues values=getContentValues(map);
        Long result =database.insert(tableName,null,values);
        return result;
    }
    /**
     * 讲map 转换成ContentValues
     * @param map
     * @return
     */
    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> result=new HashMap<>();
        Iterator<Field> filedsIterator=cacheMap.values().iterator();
        /**
         * 循环遍历 映射map的  Filed
         */
        while (filedsIterator.hasNext())
        {
            /**
             *
             */
            Field colmunToFiled=filedsIterator.next();
            String cacheKey=null;
            String cacheValue=null;
            if(colmunToFiled.getAnnotation(DbFiled.class)!=null)
            {
                cacheKey=colmunToFiled.getAnnotation(DbFiled.class).value();
            }else
            {
                cacheKey=colmunToFiled.getName();
            }
            try {
                if(null==colmunToFiled.get(entity))
                {
                    continue;
                }
                cacheValue=colmunToFiled.get(entity).toString();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            result.put(cacheKey,cacheValue);
        }

        return result;
    }

    @Override
    public Long update(T entity, T where) {
        return null;
    }

    /**
     * 创建表
     * @return
     */
    protected  abstract  String createTable();
}

##4、提供数据库操作类的工厂类:

public class BaseDaoFactory {
    private String sqliteDatabasePath;
    private SQLiteDatabase database;
    private static BaseDaoFactory instance = new BaseDaoFactory();

    private BaseDaoFactory(){
        sqliteDatabasePath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/teacher.db";
        openDatabase();
    }

    private void openDatabase() {
        this.database = SQLiteDatabase.openOrCreateDatabase(sqliteDatabasePath,null);
    }

    public static BaseDaoFactory getInstance(){
        return instance;
    }

    public synchronized <T extends BaseDao<M>,M> T getDataHeper(Class<T> clazz,Class<M> entityClass){
        T baseDao = null;
        try {
            baseDao = clazz.newInstance();
            baseDao.init(entityClass,database);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return  baseDao;
    }
}

##5、具体实现:

@DbTable("tb_user")
public class User {
    public User(String name,String password){
        this.name = name;
        this.password = password;
    }

    public User(){
    }

    @DbFiled("name")
    public String name;

    @DbFiled("password")
    public String password;
}


public class UserDao extends BaseDao {
    @Override
    protected String createTable() {
        return "create table if not exists tb_user(name varchar(20),password varchar(10))";
    }
}

##6 调用

IBaseDao<User> baseDao = BaseDaoFactory.getInstance().getDataHeper(UserDao.class,User.class);
User user = new User("teacher","123456");
baseDao.insert(user);

#四、总结
由于提供了操作dao类,我们在插入数据的时候不需要在去获取数据库对象,拼接sql要语句,直接传入一个对象即可,十分简便:
User user = new User(“teacher”,“123456”);
baseDao.insert(user);
拓展性很强,当需要重新定义一个表的时候,只需要一下几步:
##1、定义Bean:

@DbTable("tb_down")
@DbTable("tb_down")
public class DownFile {
    public DownFile(String time,String path){
        this.time = time;
        this.path = path;
    }

    public DownFile(){
    }

    @DbFiled("tb_time")
    public String time;

    @DbFiled("tb_path")
    public String path;
}

##2、定义数据操作类:

public class DownDao extends BaseDao {
    @Override
    protected String createTable() {
        return "create table if not exists tb_down(tb_time varchar(20),tb_path varchar(10))";
    }
}

##3、使用:

BaseDao<DownFile> fileBaseDao = BaseDaoFactory.getInstance().getDataHeper(DownDao.class,DownFile.class);
fileBaseDao.insert(new DownFile("2013.1.3","data/data/apth"));

#五、补充
注解的使用:为了更好的扩展性,
colmunToFiled.getAnnotation(DbFiled.class):以DownFile为例,表示成员如time,它的对应的注解值为tb_time,也就是表中的列名tb_time;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值