LazyDB :提供一种实现 Android ORM 框架的解决方案

网友投稿 765 2022-10-30

LazyDB :提供一种实现 Android ORM 框架的解决方案

LazyDB :提供一种实现 Android ORM 框架的解决方案

LazyDB

一款简易使用的orm框架

1. 框架设计

1.1. 总体流程

对于数据库的“增删改”操作,将对象输入,通过ORM框架处理,构建SQL语句,然后写入数据库,如图1所示;

对于查询数据库的操作,输入要输出对象的Class,通过ORM框架处理,构建SQL语句,查询数据库,返回后构建成Object输出,如图2所示;

1.2. ORM内部实现流程

构建SQL语句的原理:通过Java反射机制,获取Class的字段和Object字段值,通过字符串拼接构建SQL。

1.3. Java数据类型与SQLite数据类型映射表

Java数据类型SQLite数据类型
int、Integer、byte、Byte、short、Short、long、Long、Boolean、booleanINTEGER
float、Float、double、DoubleREAL
DateDATE
StringTEXT

PS:这里简单起见,将所有的字符串都用TEXT;整数都用INTEGER;

2. 内部实现的几个重要实现规则

1. 对于SQLite表字段与Java对象字段映射规则:

(1)只映射非final和非static的Java字段; (2)Java的字段名即SQLite表的字段名; (3)主键取Java对象中的名字为ID(不区分大小写)或者加了@ID注解的字段,优先查找注解;

2. 保存数据类型规则:

(1)以Java基本数据类型以及其包装类为主,还有Date;对于其他类不做处理;

3. 表名称生成规则:

(1)以Java类的完全限定名来命名(.替换为_),例如:com.andy.Person的代表的表名为com_andy_Person,保证了表名的唯一性;

3. 代码实现

介绍一下几个重要的类 (1) 用于构造SQL语句的类SQLBuilder(主要用了Java反射机制) (2) 用于执行SQL语句的类SQLiteDBExecutor (3) 提供给外部使用的ORM主类LazyDB

3.1 SQLBuilder:SQL语句构建器

该Class的主要作用是,将外部传进来的Object(对象)或者Class(类),通过Java反射机制,构建成SQL语句。

这里以创建表的SQL为例

代码步骤分解: (1)取出Class中所有Field,即Field数组; (2)遍历Field数组,找出主键的Field,拼到SQL的字符串里; (3)再次遍历Field数组,过滤掉主键的Field、final、static,拼到SQL的字符串里;

具体代码如下:

// SQLBuilder类 /** * 构建创建数据库表的sql语句 * * @param clazz 类 * @return 创建表的sql语句 */ public static String buildCreateTableSql(Class clazz) { StringBuilder sb = new StringBuilder(); Field[] fields = ReflectUtil.getDeclaredFields(clazz); if (fields == null || fields.length == 0) { throw new IllegalStateException("class'fields can not be empty"); } // 开头 sb.append("create table ") .append(TableUtil.getTableName(clazz)) // tableName .append("("); // 找到主键 Field idField = IDUtil.getIDField(fields); if (idField != null) { String idColumn = idField.getName(); ID id = idField.getAnnotation(ID.class); // 判断是有没有注解的 if (id != null && !"".equals(id.column())) { idColumn = id.column(); } DataType dataType = TableUtil.getDataType(idField.getType()); sb.append(idColumn) .append(" ") .append(dataType.toString()) .append(" primary key") .append(","); } for (Field field : fields) { if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())) {// 移除是final和static的字段 continue; } // 让不是id的field进来 if (field != idField) { sb.append(field.getName()) .append(" ") .append(TableUtil.getDataType(field.getType())) .append(","); } } // 除去最后一个逗号 if (sb.charAt(sb.length() - 1) == ',') { sb.deleteCharAt(sb.length() - 1); } sb.append(")"); String sql = sb.toString(); // debug log DeBugLogger.d("CreateTableSql", sql); return sql; }

上面代码中用到了几个工具类: ReflectUtil:用于Java反射的工具类,将所有反射调用的方法都放到这里来,统一管理,方便优化处理; IDUtil:用于主键Field查找的工具类; TableUtil:用于数据库表字段数据与Java数据类型转换、表名生成等;

3.2 SQLiteDBExecutor:SQL语句执行器

该Class的主要作用是,用于执行SQL语句,或者通过SQLiteOpenHelper执行一些数据库操作,反正所有数据库操作都在这里面。

(1)数据库非查询操作

// SQLiteDBExecutor类 /** * 执行非查询操作事物 * * @param operation 非查询操作 */ public void executeTransaction(NoQueryOperation operation) throws Exception { SQLiteDatabase db = helper.getWritableDatabase(); try { db.beginTransaction(); DeBugLogger.d("NoQuery", "beginTransaction"); if (operation != null) { operation.onOperation(db); } db.setTransactionSuccessful(); DeBugLogger.d("NoQuery", "transactionSuccessful"); } finally { db.endTransaction(); DeBugLogger.d("NoQuery", "endTransaction"); } } public interface NoQueryOperation { void onOperation(SQLiteDatabase db) throws Exception; } /** * 执行SQL,非查询操作 * @param sql SQL语句 * @throws Exception */ public void execSQL(final String sql) throws Exception { executeTransaction(new NoQueryOperation() { @Override public void onOperation(SQLiteDatabase db) throws Exception { db.execSQL(sql); } }); }

(2)数据库查询操作

// SQLiteDBExecutor类 public Cursor rawQuery(String sql, String[] selectionArgs) { SQLiteDatabase db = helper.getReadableDatabase(); return db.rawQuery(sql, null); }

然后看一段比较好看的查询代码:

List entities = lazyDB .query(Entity.class) .selectAll() .where("id=? and name=? and age=? and birthday=? and sex=? and money=?", entity.getId(), entity.getName(), entity.getAge() + "", DateUtil.date2String(entity.getBirthday()), entity.isSex() ? "1" : "0", Double.toString(entity.getMoney()) ) .findAll();

个人比较钟意这种构建器模式下的代码;看下查询代码,基于Builder模式的实现。

public class SelectBuilder { private final SQLiteDBExecutor executor; final Class objectClass; String[] columns; String whereSection; String[] whereArgs; String having; String orderBy; String groupBy; String limit; public SelectBuilder(SQLiteDBExecutor executor, Class clazz) { this.objectClass = clazz; this.executor = executor; } public SelectBuilder selectAll() { return this; } public SelectBuilder select(String... columns) { this.columns = columns; return this; } public SelectBuilder where(String whereSection, String... whereArgs) { this.whereSection = whereSection; this.whereArgs = whereArgs; return this; } public SelectBuilder having(String having) { this.having = having; return this; } public SelectBuilder orderBy(String orderBy) { this.orderBy = orderBy; return this; } public SelectBuilder groupBy(String groupBy) { this.groupBy = groupBy; return this; } public SelectBuilder limit(String limit) { this.limit = limit; return this; } ......}

提供了类似写SQL查询语句的字符串构建器; 最后,执行查询;

public class SelectBuilder { ...... /** * 执行查询操作,获取查询结果集 * * @return 数据库游标 Cursor */ public Cursor executeNative() { // 查询表是否存在 String sql = SQLBuilder.buildQueryTableIsExistSql(objectClass); Cursor cursor = executor.rawQuery(sql, null); if (cursor != null) { try { if (cursor.moveToNext()) { if (cursor.getInt(0) == 0) { return null; } } } finally { cursor.close(); } } else { return null; } //String sql = SqlBuilder.buildQuerySql(TableUtil.getTableName(objectClass), columns, whereSection, whereArgs, groupBy, having, orderBy, limit); //Cursor cursor = db.rawQuery(sql, null); // 执行查询 return executor.query(this); } /** * 执行查询操作,获取查询结果集 * * @return 查询结果集,空集则查询不到 * @throws InstantiationException * @throws IllegalAccessException * @throws NoSuchFieldException * @throws ParseException */ public List findAll() throws InstantiationException, IllegalAccessException, NoSuchFieldException, ParseException { List results = new ArrayList<>(); // 执行查询 Cursor cursor = executeNative(); if (cursor != null) { try { while (cursor.moveToNext()) { T object = ObjectUtil.buildObject(objectClass, cursor); results.add(object); } } finally { cursor.close(); } } return results; } /** * 执行查询操作,获取查询结果集的第一个 * * @return 查询结果集的第一个,null则查询不到 * @throws InstantiationException * @throws IllegalAccessException * @throws NoSuchFieldException * @throws ParseException */ public T findFirst() throws InstantiationException, IllegalAccessException, NoSuchFieldException, ParseException { T result = null; // 执行查询 Cursor cursor = executeNative(); if (cursor != null) { try { if (cursor.moveToNext()) { result = ObjectUtil.buildObject(objectClass, cursor); } } finally { cursor.close(); } } return result; }}

PS:ObjectUtil用于通过Java反射实例化对象,然后对对象进行赋值;

3.3 LazyDB:ORM入口的主类

public final class LazyDB { /** * 阻止通过new来实例化LazyDB * 应该使用create方法来创建LazyDB */ private LazyDB() { } private SQLiteDBExecutor executor; /** * 创建默认配置的数据库 * * @param context 上下文 */ public static LazyDB create(Context context) {} ...... /** * 创建表 * * @param clazz 类 */ public void createTable(Class clazz) throws Exception {} /** * 创建表 * * @param tableName 表名 * @param idColumn id * @param idDataType id的类型 * @param isAutoIncrement 是否自动增长 * @param columns 其他列名,不包括id */ public void createTable(String tableName, String idColumn, String idDataType, boolean isAutoIncrement, String... columns) throws Exception {} /** * 删除表 * * @param clazz 类 */ public void dropTable(final Class clazz) throws Exception {} /** * 删除数据库中所有的表 */ public void dropAllTables() throws Exception {} /** * 查询所有表名 * * @return 所有表名的集合;若没有表,则是空集合 */ public List queryAllTableNames() {} /** * 从表中查找出所有字段名 * * @param clazz class * @return 字段列表 * @throws NoSuchFieldException * @throws InstantiationException * @throws ParseException * @throws IllegalAccessException */ public List queryAllColumnsFromTable(Class clazz) throws NoSuchFieldException, InstantiationException, ParseException, IllegalAccessException {} /** * 表是否存在 * * @param clazz 类 * @return true 表存在,false 表不存在 */ public boolean isTableExist(Class clazz) {} /** * 判断对象是否存在数据库中 * * @param object 对象 * @return true 存在,false 不存在 * @throws IllegalAccessException */ public boolean isObjectExist(Object object) throws IllegalAccessException {} /** * 插入对象 * * @param object 对象 */ public void insert(@NonNull Object object) throws Exception {} /** * 插入多个对象数据 * * @param objectList 对象集合 * @throws IllegalAccessException */ public void insert(@NonNull final List objectList) throws Exception {} /** * 更新对象 * * @param object 对象 * @throws IllegalAccessException */ public void update(@NonNull final Object object) throws Exception {} /** * 插入或更新对象 * * @param object 对象 * @throws IllegalAccessException */ public void insertOrUpdate(@NonNull Object object) throws Exception {} /** * 删除对象 * * @param object 对象 * @throws IllegalAccessException */ public void delete(@NonNull final Object object) throws Exception {} /** * 删除多个object集合 * * @param objectList object集合 * @throws IllegalAccessException */ public void delete(@NonNull final List objectList) throws Exception {} /** * 删除数据 * * @param clazz 类 * @param whereClause 例如:id=? * @param whereArgs ?的值 */ public void delete(final Class clazz, final String whereClause, final String[] whereArgs) throws Exception {} /** * 执行查询操作 * * @param clazz 类 * @return select操作的构建器 */ public SelectBuilder query(Class clazz) {} /** * 通过id查询 * * @param clazz 类 * @param idValue idValue * @return object * @throws NoSuchFieldException * @throws InstantiationException * @throws ParseException * @throws IllegalAccessException */ public T queryById(Class clazz, Object idValue) throws Exception {}

4. Java反射优化方案

Java反射机制虽然好用,但是为此会牺牲性能,这里有个优化点,可以在取反射时,加一层内存缓存,先查缓存,找不到再取反射。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:comp3411 - week2 notes- Informed (Heuristic) Search
下一篇:windows下如何管理多个github账号
相关文章

 发表评论

暂时没有评论,来抢沙发吧~