2

我对 Java 还很陌生,我想创建一个包含 Map 对象的 DefaultMutableTreeNode 类。

我编写了一个继承自更通用 TreeNode 类的 TreeNodeMap 类,该类又继承自 DefaultMutableTreeNode。

TreeNodeMap 类包含方法populate,它采用相当长的参数列表。我计划通过将其中一些参数转换为单个对象并重载方法来提高方法的可读性,这样我就不必在第一次调用中传递一组空值(递归)。

注意:如果您不关心我对该方法的详细说明,请直接从此处跳至代码

最初我创建了一个空节点,它只包含子节点但不包含数据,这是 ROOT。这个想法是有一个方法,允许调用者传递任何带有“field_id”、“field_label”、“parent_id”列的查询。在初始调用中,查询通过 Where 子句传递,其中“parent_id 为空”,因此得到所有没有父节点的节点。所有这些节点都添加到 ROOT 节点。在遍历结果集时,调用每个节点的填充方法现在传递一个“Where 子句”,其中 parent_id = [当前节点 id] 从而获取该节点的所有子节点。这将递归地发生,直到所有节点都具有层次结构。

代码 (请记住,我是 JAVA 新手,因此感谢您提供任何反馈)

public void populate( boolean isRoot, String parentFieldId, String parentFieldLabel, String childFieldId, String childFieldLabel, 
            int parentId, String tableName, String whereClause, String orderByClause, String additionalColumns, List<Map<String, String>> queryParams) throws SQLException, Exception{
        ResultSet rs = null;
        Connection con = null;
        PreparedStatement ps = null;
        try{

            DBConnection dbConnection = new DBConnection("localhost", 3306, "root", "password", "test", DBDrivers.DBTYPE_MYSQL);
            con = dbConnection.getConnection();

            String treeNodeSql = "Select " + parentFieldId + ", " + parentFieldLabel + 
                                                ", " + childFieldId + ", " + childFieldLabel;
            if(additionalColumns != null && additionalColumns.trim().length() > 0)
                treeNodeSql +=  " ," + additionalColumns;

            treeNodeSql += " From " + tableName + " WHERE 1=1";

            if(whereClause != null && whereClause.trim().length() > 0 ){
                treeNodeSql += " AND " + whereClause;
            }

            if(isRoot){
                treeNodeSql += " AND " + parentFieldId + " is null";
            }else{
                if(parentFieldId == null || parentFieldId.trim().length() == 0)
                    throw new Exception(" The populate() method requires a parentId when isRoot is false.");
                treeNodeSql += " AND " + parentFieldId + " = ?";
            }
                //order clause append
            if(orderByClause != null && orderByClause.trim().length() > 0)
                treeNodeSql += " " + orderByClause;

                //prepare statement
             ps = con.prepareStatement(treeNodeSql); 
            int ixParam = 0;

                for(Map qParam : queryParams){
                    if(qParam.get("datatype") == "int"){
                        ps.setInt(++ixParam, Integer.parseInt((String) qParam.get("value")));
                    }else if(qParam.get("datatype") == "string"){
                        ps.setString(++ixParam, (String) qParam.get("value"));
                    }
                }

            out.println(treeNodeSql);
            if(parentId > 0){
                ps.setInt(queryParams.size()+1, parentId);
            }
            rs = ps.executeQuery();

            while(rs.next()){
                HashMap<String, Object> childNodeData = new HashMap<String, Object>(4);
                childNodeData.put("parentFieldId", parentFieldId);
                childNodeData.put("parentFieldIdValue", Integer.toString(rs.getInt(parentFieldId)));
                childNodeData.put("parentFieldLabel", parentFieldLabel);
                childNodeData.put("parentFieldLabelValue", rs.getString(parentFieldLabel));
                childNodeData.put("childFieldId", childFieldId);
                childNodeData.put("childFieldIdValue", Integer.toString(rs.getInt(childFieldId)));
                childNodeData.put("childFieldLabel", childFieldLabel);
                childNodeData.put("childFieldLabelValue", rs.getString(childFieldLabel));

                out.println("parentId: " + rs.getInt(parentFieldId)
                                + ", parentLabel: " + rs.getString(parentFieldLabel)
                                + ", childId: " + rs.getInt(childFieldId)
                                + ", childLabel: " + rs.getString(childFieldLabel));
                TreeNodeMap childNode = new TreeNodeMap(childNodeData);
                this.add(childNode);
                childNode.populate(false, parentFieldId, parentFieldLabel, childFieldId, childFieldLabel, rs.getInt(childFieldId), tableName, whereClause, orderByClause, additionalColumns, queryParams);
            }
        }catch(SQLException e){
            throw e;

        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            out.println(e.getCause());
            out.println(e.getMessage());
            e.printStackTrace();
            throw e;
        }finally {
            try { rs.close(); } catch (Exception e) {  }
            try { ps.close(); } catch (Exception e) {  }
            try { con.close(); } catch (Exception e) {  }
        }
    }   

对该方法的初始调用如下所示:

treeNode.populate(true, "supervisor_id", "supervisor", "employee_id", "employee", 0, "vw_employee", null, null, null, queryParams);

我使用这种方法看到的问题是数据库将被查询 X 次,并且对于大数据集,我认为这会导致一些问题。我还为每个查询打开一个连接!因此,我考虑在创建方法后将 Connection 传递给该方法(在递归调用中),但是我不确定如何适当地关闭它。我可以编写一个条件来检查节点是否为 ROOT,然后关闭连接,但如果代码在两者之间失败会发生什么。

所以最后我的问题是:1-解决这个问题的最佳方法是什么?2-我是否应该传递连接,以便在树的填充期间只有一个连接保持打开状态?如果是,那么我该如何正确关闭它。3-我应该将结果集缓存到 ArrayList 中并改用它吗?

4

1 回答 1

3

您的性能问题可能是有根据的。反而,

  1. 实施TreeModel,如​​图所示FileTreeModel。这样,只需要查询可见节点。这里有一个相关的例子。

  2. 通过javax.sql.DataSource,而不是Connection

  3. 您的类implements TreeModel可以封装任何缓存的数据,但也提供一些更新过时条目的方法。显示缓存值后,考虑使用SwingWorker刷新模型,如下所示。而不是List<Record>,您可能想要查看Map<PrimaryKey, Record>.

于 2012-06-24T16:29:58.973 回答