移动架构29_面向对象式手写数据库架构设计一(基本框架与插入数据)
2017-10-26 22:28
609 查看
Demo地址:
https://gitee.com/YuBaoZi/codes/nujo5r0xsvdyte9pq7lha77
建议:代码很简单,建议敲两边就能理解了,很实用;
效果:
数据库查看工具:SqliteLookup
(2)根据业务Bean生成一个表中列名和Bean的方法名对应的集合,由于实际中成员名和列名可能不同,通过注解实现“翻译;
(3)解析业务Bean,将业务Bean中的成员名和(2)中的集合比对,生成一个列名对应Bean的value的集合
(4)将(3)中的集合转换成数据库识别的内容(contentValue),设置到数据库中去
工厂类:接受泛型,产生对应的数据库操作类
-> 接口:封装插入、修改的行为、限制类型;
-> 数据库抽象操作类:解析传入的业务Bean,生成可以直接进行数据库操作的API;定义操作类的类型
-> 具体操作类:实现具体不同表的创建
-> Bean:表的表名、列名封装;方便具体的业务操作;
3、封装解析业务Bean(也就是T类型)的抽象类
User user = new User(“teacher”,”123456”);
baseDao.insert(user);
拓展性很强,当需要重新定义一个表的时候,只需要一下几步:
colmunToFiled.getAnnotation(DbFiled.class):以DownFile为例,表示成员如time,它的对应的注解值为tb_time,也就是表中的列名tb_time;
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;
相关文章推荐
- 移动架构30_面向对象式手写数据库架构设计二(修改、删除、查询、拓展)
- 面向对象式手写数据库架构
- 面向对象式手写数据库框架
- Hibernate框架的基本搭建(一个小的java project的测试向数据库中插入和查询数据的功能)
- [开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [一] 初衷与架构设计
- ssm框架,往数据库插入一条数据,返回插入数据的id
- MVC设计模式下的Dao的设计以及基础框架的搭建(以对数据库进行插入和查询为例)
- Android架构设计01-数据库框架
- 基于java的网络爬虫框架(实现京东数据的爬取,并将插入数据库)
- 框架设计:实现数据的按需更新与插入的改进
- 数据库 Mocrosoft SQL Server 基本语句 建表 插入数据
- 数据建模与数据库设计——基本概念
- 微信公号“架构师之路”学习笔记(五)-数据库扩展性架构设计(水平切分,秒级扩容,平滑迁移,在线表结构变更,一个大数据量多属性高并发的数据库设计等)
- [开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [一] 初衷与架构设计 - ModestMT.Zou - 博客园
- [置顶] 基于java的网络爬虫框架(实现京东数据的爬取,并将插入数据库)
- java基本数据类型初始值(默认值) ,在设计数据库时造成的问题
- 王家林最受欢迎的一站式云计算大数据和移动互联网解决方案课程 V1之Android架构设计和实现完整训练:HAL&Framework&Native Service&Android Service&Bes
- 移动架构之数据库框架
- 数据仓库(八):数据仓库中数据库设计的基本模型对比--Inmon
- 框架设计:实现数据的按需更新与插入的改进