这是另一个有争议的主题,但这次我只寻找简单且有记录的答案。场景:

我们假设以下方法:

 public static Hashtable<Long, Dog> getSomeDogs(String colName, String colValue) {
  Hashtable<Long, Dog> result = new Hashtable<Long, Dog>();
  StringBuffer sql = null;
  Dog dog = null;
  ResultSet rs = null;
      try {
          sql = new StringBuffer();
          sql.append("SELECT * FROM ").append("dogs_table");
          sql.append(" WHERE ").append(colName).append("='");
          sql.append(colValue).append("'");
          rs = executeQuery(sql.toString());
              while (rs.next()) {
                  dog= new Dog();
                  //...initialize the dog from the current resultSet row
              result.put(new Long(dog.getId()), dog);
              }
          }
     catch (Exception e) {
         createErrorMsg(e);
         result = null; //i wonder....
         }
     finally {
         closeResultSet(rs); //this method tests for null rs and other stuff when closing the rs.
     }
   return result;
 }

问题 :

1.您建议采取哪些方法来改进这种带有某些属性的归还狗的技术?

2.rs.next() 将为 null ResultSet 返回 false,或者生成异常,如下所示:

字符串 str = null;System.out.println(str.toString());

3.如果在从 ResultSet 的当前行初始化狗对象时,发生了一些不好的事情,例如:连接失败、不兼容的值已传递给狗属性设置器等?现在哈希表中可能有 10 个元素,或者没有(第一行)。下一步行动是什么:a) 返回空哈希表;b) 返回结果哈希表,与此阶段的情况相同;c) 抛出异常:这里的异常类型是什么?

4.我想你们都会同意这一点:没有什么不好的事情发生,询问中没有行,将返回空值。然而,@Thorbjørn Ravn Andersen 说 这里 我应该返回一个 NullObject 而不是空值。我想知道那是什么。

5.我注意到有人和一群人说应该将应用程序分成层或某种级别。考虑上面的例子,除了我能想到的这些之外,这里还有哪些层:

第 1 层::数据库层,执行操作的地方:这个方法。

第二层::???:构造新 Dog 对象的某个层:我的狗对象。

第三层::?:我打算对狗的集合做一些事情的某个层:GUI 层主要是用户界面的子层。

按照应用程序流程,如果第一层发生异常,最好的处理方法是什么?我的想法 :捕获异常,记录异常,返回一些值。这是最佳实践吗?

曼尼感谢您的回答,我期待看看其他人对这些问题的看法。

有帮助吗?

解决方案

你问的五个问题

1.什么样的方式做u建议改进这种技术的返回的有些狗,有一些属性?

几个,其实。

  • 你的方法是静态的,-这不是可怕的,但是导致你使用的另一个静态"executeQuery",这气味的单独我...
  • 类"狗"违反OO命名实践的复数的名词不作良好的类名称,除非一个实例类拥有一个收集的事情-看来,狗实际上是"狗"。
  • HashTable 是所有的但已过时。哈希或ConcurrentHashMap得到更好的性能。
  • 我不能看到的原因,要创建第一个部分的查询与多个追加-这不是坏的,但它不太可读于它的可能,因此sql。append("SELECT*from dogs_table WHERE");使得一个更合理的开始,如果你只是硬编码选择的列(*),并表的姓名(dogs_table)无论如何。

2.rs。下一个()will return false for null结果,或者会产生一个例外

这似乎并不是一个问题,但是,rs。下一个()returns false尽快还有不再有任何行过程。

3.什么如果,而初始化狗目从目前排的结果,一些不好的事情发生

如果"有什么不好的事情发生",你做什么,接下来是给你和你的设计。还有宽容的办法(返回的所有行可),并无情的(扔一个例外)。我往往倾向于将"无情"的做法,因为具有"原谅"的方法,用户就不会知道你有没有返回的所有行,存在的只是所有那些你会得到之前的错误。但是有可能的情况下为宽容的办法。

4.我想你也会都同意这一:没有什么不好的事情发生,有没有上的行审讯,一个空值将返回。

这不是什么东西在这里有一个明显的 答案。第一,这不是发生了什么方法编写的。它将要返回的一个空HashTable(这意味着什么"空对象").第二,空并不总是该回答"没有结果发现"情况。

我看见过空的,但我也见过空的结果的变量,而不是。我要求他们都是正确的办法,但我更喜欢空的结果的变量。然而,它始终最好是一致的,所以选择的方法返回"没有结果",并坚持下去。

5.我已经注意到的人和群体的人说,应该分割的应用程序进层,或级别的一种。

这是难以回答的比其他人没有看到你的余的应用程序。

其他提示

我会避免以下情况

   sql.append("SELECT * FROM ").append("dogs_table");
   sql.append(" WHERE ").append(colName).append("='");
                        sql.append(colValue).append("'");

并使用 准备好的声明 及其关联的参数设置方法(setString()) ETC。这将防止值出现问题 colValue 有引号和 SQL 注入攻击(或者更一般地说, colValue 形成一些 SQL 语法)。

我会 绝不 如果集合仅为空,则返回 null。这似乎非常违反直觉,从客户的角度来看完全出乎意料。

我不建议在错误情况下返回 null,因为您的客户端必须明确检查这一点(并且可能会忘记)。如果需要的话,我会返回一个空集合(这可能类似于您的评论 re.空对象),或更可能抛出异常(取决于情况和严重性)。异常很有用,因为它会携带一些与遇到的错误相关的信息。Null 没有告诉你任何信息。

如果在构建过程中遇到问题该怎么办 Dog 目的 ?我认为这取决于您希望应用程序的健壮性和弹性。返回子集是否有问题 Dogs,或者这将是完全灾难性的,您需要报告这一点?这是一个应用程序要求(我过去必须满足这两种情况 - 最大努力 或者 全有或全无).

一些观察。我会用 哈希映射 而不是旧的 Hashtable (对所有访问进行同步,更重要的是,不是适当的 Collection - 如果你有 Collection 你可以将它传递给任何其他期望的方法 任何 Collection), 和 字符串生成器 超过 StringBuffer 出于类似的原因。这不是一个大问题,但值得了解。

空对象模式是其中您一个设计图案总是返回一个目的是避免NPE:S和在代码任何null检查。在您的情况下,这意味着,而不是返回null,返回一个空Hashtable<Long, Dogs>代替。

的原因是因为它是一个收集和你的其他代码访问它,因此,它不会打破,如果你返回一个空的集合;它不会通过,它将不包含任何令人惊讶的迭代,它不会引起NPE:■被抛出和诸如此类的东西

要准确地说,一个空对象是一个特殊的实施类/接口,也绝对没有什么并因此具有任何种类的无副作用的。由于不是使用它会使你的代码更加清晰null的性质,因为当你知道,你永远从你的方法调用获得对象的无论在方法内部发生了什么的你甚至不要检查空值,也没有做出反应的代码给他们!因为空对象没有做任何事情,你甚至可以让他们为的单身的只是躺在附近,因此通过这样做节省内存。

不要连接字符串建立SQL查询,就像你正在做的:

sql = new StringBuffer();
sql.append("SELECT * FROM ").append("dogs_table");
sql.append(" WHERE ").append(colName).append("='");
sql.append(colValue).append("'");

这使你的代码容易受到众所周知的安全攻击, SQL注入。相反,这样做的,使用PreparedStatement并通过调用就可以了适当set...()方法设置的参数。请注意,您只能使用此设置列的的,你不能用它来动态地构造一个列的名称的,因为你在干什么。例如:

PreparedStatement ps = connection.prepareStatement("SELECT * FROM dogs_table WHERE MYCOL=?");
ps.setString(1, colValue);

rs = ps.executeQuery();

如果您使用的是PreparedStatement,JDBC驱动程序会自动照顾逃避某些字符可能存在于colValue,使SQL注入攻击不工作了。

如果发生错误,抛出异常。如果没有数据,返回一个空的集合,不是空。 (另外,通常你应该返回更加通用的“地图”,而不是具体的实现),

你可以显着减少量的样板JDBC通过使用代码 弹簧JDBC 而不是普通的老JDBC。这里是相同的方法改写使用弹簧JDBC

public static Hashtable<Long, Dogs> getSomeDogs(String colName, String colValue) {

    StringBuffer sql = new StringBuffer();
    sql.append("SELECT * FROM ").append("dogs_table");
    sql.append(" WHERE ").append(colName).append("='");
    sql.append(colValue).append("'");

    Hashtable<Long, Dogs> result = new Hashtable<Long, Dogs>();

    RowMapper mapper = new RowMapper() {

        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            Dogs dog = new Dogs();
            //...initialize the dog from the current resultSet row
            result.put(new Long(dog.getId()), dog);
        }
    };
    (Hashtable<Long, Dogs>) jdbcTemplate.queryForObject(sql, mapper);
}

春天需要照顾:

  1. 遍历的结果
  2. 关闭的结果
  3. 处理异常一贯地

正如其他人已经提到的,你真的应该用一个预处理构造SQL而不是一串(或StringBuffer).如果由于某种原因你不能这样做,可以改善的可读性的查询通过建立SQL喜欢这个代替:

    String sql = 
        "SELECT * FROM dogs_table " +
        "WHERE " + "colName" + " = '" + colValue + "'";
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top