一起来写个SQLite ORM数据库框架(下)

2024-06-10 08:32

本文主要是介绍一起来写个SQLite ORM数据库框架(下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

接上一节 一起来写个SQLite ORM数据库框架(上) 这节讲下代码实现。
首先有4个注解类:表名注解-Table、主键注解-PrimaryKey、列注解-Column、非数据库字段注解-NotDBColumn。因为篇幅的原因 这里只单独看看新增的实现 其他都类似

列注解类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {String value() default "";String defaultValue() default "";
}

列注解对应的对象实体类(ColumnEntity ):

public class ColumnEntity {/*** 实体类中的属性字段*/private Field field;private String columnName;private String defaultValue;/*** 获取指定对象的当前字段的值* @param entity    获取字段值的对象* @return*/public Object getValue(Object entity) {if(entity != null) {try {//设置属性是可以访问的field.setAccessible(true);return field.get(entity);} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}return null;}/*** 设置指定对象的当前字段的值* @param entity    获取字段值的对象* @return*/public void setValue(Object entity, Cursor cursor) throws Exception{Class<?> fieldType = field.getType();try {int columnIdx = cursor.getColumnIndex(columnName);if(columnIdx == -1) {//当前游标中没有该字段的值return;}field.setAccessible(true);if(fieldType==int.class||fieldType==Integer.class) {field.set(entity, cursor.getInt(columnIdx));return;}if(fieldType==char.class||fieldType==String.class){field.set(entity, cursor.getString(columnIdx));return;}if(fieldType==long.class||fieldType==Long.class){field.set(entity, cursor.getLong(columnIdx));return;}if(fieldType==float.class||fieldType==Float.class){field.set(entity, cursor.getFloat(columnIdx));return;}if(fieldType==double.class||fieldType==Double.class){field.set(entity, cursor.getDouble(columnIdx));return;}} catch (Exception e) {throw e;}}//    public Field getField() {
//        return field;
//    }public void setField(Field field) {this.field = field;}public String getColumnName() {return columnName;}public void setColumnName(String columnName) {this.columnName = columnName;}public String getDefaultValue() {return defaultValue;}public void setDefaultValue(String defaultValue) {this.defaultValue = defaultValue;}
}

解析注解映射对象管理类(TableEntityManager ):

public class TableEntityManager {/*** 每张表的相关信息缓存集合*/private static HashMap<Object, TableEntity> mTableMap = new HashMap<Object, TableEntity>();/*** 获取EntityTable对象*/public static <T> TableEntity getTableEntity(T entity) {return getTableEntity(entity.getClass());}public static <T> TableEntity getTableEntity(Class<?> mClass) {if(mTableMap.containsKey(mClass)) {return mTableMap.get(mClass);} else {return createTableEntity(mClass);}}public static TableEntity createTableEntity(Class<?> mClass) {TableEntity tableEntity = new TableEntity();//设置表名setTableName(tableEntity,mClass);//设置主键和列setColumnList(tableEntity,mClass);mTableMap.put(mClass, tableEntity);return tableEntity;}/*** 解析注解设置表名*/public static void setTableName(TableEntity tableEntity,Class<?> mClass) {Table table = mClass.getAnnotation(Table.class);if(null==table||TextUtils.isEmpty(table.value())) {tableEntity.setTableName(mClass.getSimpleName());}tableEntity.setTableName(table.value());}/*** 解析注解设置主键(PrimaryKeyEntity)*/public static boolean setPrimaryKey(TableEntity tableEntity,Field field){PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class);if(null == primaryKey) {return false;}if(primaryKey.isAutoGenerate() && field.getType()!=long.class && field.getType()!=int.class){throw new RuntimeException("自增长主键字段类型不正确,请设置自增长字段类型为long或者int");}PrimaryKeyEntity primaryKeyEntity = new PrimaryKeyEntity();primaryKeyEntity.setField(field);if(TextUtils.isEmpty(primaryKey.value())) {//没有通过注解设置列名,默认取字段名称为列名primaryKeyEntity.setColumnName(field.getName());} else {primaryKeyEntity.setColumnName(primaryKey.value());}primaryKeyEntity.setAutoGenerate(primaryKey.isAutoGenerate());//获取是否自动增长tableEntity.setPrimaryKey(primaryKeyEntity);return true;}/*** 解析注解获得字段列名和默认值并封装到 ColumnEntity*/public static void setColumnList(TableEntity tableEntity,Class<?> mClass) {Field[] fields = mClass.getDeclaredFields();List<ColumnEntity> columnList = new ArrayList<ColumnEntity>();ColumnEntity columnEntity = null;for(Field field:fields){if (Modifier.isStatic(field.getModifiers())) {//过滤掉static静态字段continue;}if(field.getType() == Object.class) {//过滤掉非基本类型字段continue;}NotDBColumn notDbColumn = field.getAnnotation(NotDBColumn.class);if(null != notDbColumn) {//非数据库字段不作处理continue;}if(null==tableEntity.getPrimaryKey()){ //判断是否有主键注释 并设置主键if(setPrimaryKey(tableEntity,field)){continue;}}//获取每个字段的注解Column column = field.getAnnotation(Column.class);columnEntity = new ColumnEntity();columnEntity.setField(field);// 解析注解设置列名,默认取字段名称为列名String columnName = field.getName();if(column != null) {if (!TextUtils.isEmpty(column.value())) {columnName = column.value();}if(!TextUtils.isEmpty(column.defaultValue())){columnEntity.setDefaultValue(column.defaultValue());}}columnEntity.setColumnName(columnName);columnList.add(columnEntity);}tableEntity.setColumnList(columnList);}
}

拼接SQL语句类(SQLBuilder) 这里说下在拼创建表的sql的时候 我并没有把字段类型拼上 这是由于对于sqllite数据库 它有个特点就是可以是无类型的 意思就是你给它什么类型 它就会存什么类型 所以我省去转化类型的步骤

//拼接插入的sql语句
public static <T> BindSQL getInsertSQL(TableEntity tableEntity,T entity){StringBuilder sql = new StringBuilder();StringBuilder valueSql = new StringBuilder();int size = tableEntity.getColumnList().size();Object[] args = new Object[size+1];sql.append("INSERT INTO ").append(tableEntity.getTableName()).append("(");valueSql.append(" VALUES(");int i = 0;PrimaryKeyEntity primaryKey = tableEntity.getPrimaryKey();if(null!=primaryKey&&!primaryKey.isAutoGenerate()){sql.append(primaryKey.getColumnName()+",");valueSql.append("?,");args[i++] = primaryKey.getValue(entity);}for (ColumnEntity columnEntity:tableEntity.getColumnList()){Object valueObj = columnEntity.getValue(entity);if(null!=valueObj){sql.append(columnEntity.getColumnName());sql.append(",");valueSql.append("?");valueSql.append(",");args[i++] = columnEntity.getValue(entity);}}sql.deleteCharAt(sql.length() - 1);valueSql.deleteCharAt(valueSql.length()-1);sql.append(")");valueSql.append(")");sql.append(valueSql);Object[] args2 = new Object[i];System.arraycopy(args,0,args2,0,i);return new BindSQL(sql.toString(),args2);};

执行数据库操作管理类(SQLExecuteManager ):

/*** 新增一条数据*/
public <T> long insert(T entity){TableEntity tableEntity = TableEntityManager.getTableEntity(entity);BindSQL bindSQL = SQLBuilder.getInsertSQL(tableEntity,entity);long rowId =  insert(bindSQL.getSql(),bindSQL.getBindArgs());return rowId;
}

框架入口类(SQLiteDB)

 /*** 新增一条数据*/public <T> long insert(T entity){return mSQLExecuteManager.insert(entity);}

整个easyDB数据库框架的大体结构就介绍到这里了,大家可以下载源码查看更多实现 ,还有很多不足的地方 比如不支持多数据库,线程安全等 也可以自行扩展。

这篇关于一起来写个SQLite ORM数据库框架(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1047664

相关文章

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Java 缓存框架 Caffeine 应用场景解析

《Java缓存框架Caffeine应用场景解析》文章介绍Caffeine作为高性能Java本地缓存框架,基于W-TinyLFU算法,支持异步加载、灵活过期策略、内存安全机制及统计监控,重点解析其... 目录一、Caffeine 简介1. 框架概述1.1 Caffeine的核心优势二、Caffeine 基础2

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

Oracle数据库在windows系统上重启步骤

《Oracle数据库在windows系统上重启步骤》有时候在服务中重启了oracle之后,数据库并不能正常访问,下面:本文主要介绍Oracle数据库在windows系统上重启的相关资料,文中通过代... oracle数据库在Windows上重启的方法我这里是使用oracle自带的sqlplus工具实现的方

MySQL批量替换数据库字符集的实用方法(附详细代码)

《MySQL批量替换数据库字符集的实用方法(附详细代码)》当需要修改数据库编码和字符集时,通常需要对其下属的所有表及表中所有字段进行修改,下面:本文主要介绍MySQL批量替换数据库字符集的实用方法... 目录前言为什么要批量修改字符集?整体脚本脚本逻辑解析1. 设置目标参数2. 生成修改表默认字符集的语句3

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

如何通过try-catch判断数据库唯一键字段是否重复

《如何通过try-catch判断数据库唯一键字段是否重复》在MyBatis+MySQL中,通过try-catch捕获唯一约束异常可避免重复数据查询,优点是减少数据库交互、提升并发安全,缺点是异常处理开... 目录1、原理2、怎么理解“异常走的是数据库错误路径,开销比普通逻辑分支稍高”?1. 普通逻辑分支 v

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1