JFinal源码走读_4_ActiveRecord CURD分析

ActiveRecord CURD分析

ActiveRecord初始化时,将Table对象与数据表进行了映射关联,那么activerecord又是如何实现与数据库交互的呢

  • 所有的自定义model都会继承Model
    类,而Model类封装了常用的数据库操作
  • Model通过Table来处理具体的映射关系
  • Model使用Map

Model的save方法探秘

public boolean save() { // 获取config,此config是初始化时放进DbKit中的 Config config = getConfig(); // 获取当前model对应的table实例 Table table = getTable(); //声明一个sql语句的承载对象 StringBuilder sql = new StringBuilder(); //声明一个paras集合 List<Object> paras = new ArrayList<Object>(); //通过方言处理器生成针对指定数据库的sql语句 //针对mysql生成的语句:insert into `blog`(`content`, `id`, `title`) values(?, ?, ?) config.dialect.forModelSave(table, attrs, sql, paras);

        Connection conn = null;
        PreparedStatement pst = null; int result = 0; try {
            conn = config.getConnection(); // 不了解此方法对oracle和mysql的支持情况 if (config.dialect.isOracle())
                pst = conn.prepareStatement(sql.toString(), new String[]{table.getPrimaryKey()}); else pst = conn.prepareStatement(sql.toString(), Statement.RETURN_GENERATED_KEYS); // 填充pst config.dialect.fillStatement(pst, paras); // 取得返回值sql语句执行的结果 result = pst.executeUpdate(); // 应是对oracle的专属方法 getGeneratedKey(pst, table); // 清空modifyFlag getModifyFlag().clear(); // result >=1 说明sql语句执行成功 return result >= 1;
        } catch (Exception e) { throw new ActiveRecordException(e);
        } finally {
            config.close(pst, conn);
        }
    }

####find(Connection conn, String sql, Object… paras)方法探秘

此方法签名:private List find(Connection conn, String sql, Object… paras) throws Exception
所有对数据库的查询操作,都与此方法的实现类似

private List<M> find(Connection conn, String sql, Object... paras) throws Exception {
        Config config = getConfig();
        Class<? extends Model> modelClass = getClass(); if (config.devMode)
            checkTableName(modelClass, sql);

        PreparedStatement pst = conn.prepareStatement(sql);
        config.dialect.fillStatement(pst, paras);
        ResultSet rs = pst.executeQuery(); // 将数据库的返回的结果集转变为java世界的Model集合,延后分析 List<M> result = ModelBuilder.build(rs, modelClass); // 善后工作 DbKit.closeQuietly(rs, pst); return result;
    }
List result = ModelBuilder.build(rs, modelClass)探索
public static final <T> List<T> build(ResultSet rs, Class<? extends Model> modelClass) throws SQLException, InstantiationException, IllegalAccessException {
        List<T> result = new ArrayList<T>(); // 与初始化类似,只是获取的不一定是表的全部列属性 ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount();

        String[] labelNames = new String[columnCount + 1]; int[] types = new int[columnCount + 1]; // 填充上面定义的labelNames和types buildLabelNamesAndTypes(rsmd, labelNames, types); while (rs.next()) { // 创建新的model对象来承载结果集中的数据 Model<?> ar = modelClass.newInstance();
            Map<String, Object> attrs = ar.getAttrs(); // 循环填充attrs for (int i=1; i<=columnCount; i++) {
                Object value; // 处理二进制数据 if (types[i] < Types.BLOB)
                    value = rs.getObject(i); else if (types[i] == Types.CLOB)
                    value = handleClob(rs.getClob(i)); else if (types[i] == Types.NCLOB)
                    value = handleClob(rs.getNClob(i)); else if (types[i] == Types.BLOB)
                    value = handleBlob(rs.getBlob(i)); //非二进制,直接取出 else value = rs.getObject(i); // 将所获得的value放入attrs attrs.put(labelNames[i], value);
            } // 添加model到result集合中 // 至此,完成了orm映射的双向映射,model->表->model result.add((T)ar);
        } return result;
    }

小结

还有其他的许多实用的数据库操作方法,大体与上两种方式类似,不一一探究。
activeRecord省去了诸如hibernate的映射定义和mybatis的sql映射,以及这些框架必备的配置文件。且默认的model已经实现了常用的数据库操作,使框架的使用者几乎不用书写dao层的具体代码,只需实现几个Model的子类即完成了持久层的建设。
几个核心
* 通过规范的数据库字段命名(作者推荐驼峰命名法),以键值对的方式存储从数据库中得到的数据,可以很方便对扩展的model的属性进行维护。
* 整个activerecord 以table对象为桥梁,使Model能够与具体的数据表相关联。
* 通过Dialect类,使用模板方法模式,实现对多种数据库的支持

你可能感兴趣的:(java,orm,javaweb,源码分析,jFinal)