代码之家  ›  专栏  ›  技术社区  ›  hypercube

Java和SQL:返回null还是抛出异常?

  •  4
  • hypercube  · 技术社区  · 16 年前

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

    让我们假设以下方法:
     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()对于空ResultSet将返回false,或者将生成异常,如下所示:

    4.我想你们都会同意这一点:没有什么不好的事情发生,审讯中没有行,将返回一个空值。然而,@托尔比约恩·拉文·安徒生说 here

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

    Layer1::执行操作的数据库层:此方法。

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

    第三层:?:我打算对狗的集合做点什么的某个层:主要是GUI层,或者是用户界面的一个子层。

    在应用程序流程之后,如果第一层发生异常,最好怎么处理?我的想法是:捕获异常,记录异常,返回一些值。这是最好的做法吗?

    曼尼,谢谢你的回答,我期待着看到其他人对这些事情的看法。
    6 回复  |  直到 9 年前
        1
  •  6
  •   CPerkins    16 年前

    我会避免以下情况

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

    PreparedStatement setString() )等等。这将防止以下值出现问题 colValue 具有引号和SQL注入攻击(或更一般地, 列值

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

    我不建议在错误条件下返回null,因为您的客户端必须明确检查这一点(并且可能会忘记)。如果需要,我会返回一个空集合(这可能类似于您对null对象的评论),或者更可能抛出异常(取决于具体情况和严重程度)。该异常非常有用,因为它将携带与遇到的错误相关的一些信息。空告诉你什么也没说。

    Dog 全赢或全输的 ).

    几点观察。我会用 HashMap Hashtable Collection -如果你有 任何 StringBuilder 超过 StringBuffer

        2
  •  8
  •   Brian Agnew    16 年前

    1.你建议如何改进这种归还带有某种属性的狗的技术?

    • 类“Dogs”违反了面向对象的命名惯例——除非类的一个实例包含一组东西,否则复数名词不能成为好的类名——而且看起来Dogs实际上是“Dog”。
    • 几乎已被弃用。HashMap或ConcurrentHashMap具有更好的性能。
    • 我看不出有什么理由在查询的第一部分创建多个附加项——这还不错,但可读性不如预期,所以sql.append(“SELECT*FROM dogs_table WHERE”);如果你只是要硬编码所选的列(*)和表名(dogs_table),那么这是一个更明智的开始。

    2.rs.next()对于空ResultSet将返回false,或者将生成异常

    这似乎不是一个问题,但是的,一旦不再有任何行需要处理,rs.next()就会返回false。

    3.如果在从ResultSet的当前行初始化dog对象时发生了错误怎么办

    如果“发生了不好的事情”,你接下来要做什么取决于你和你的设计。有宽恕的方法(返回所有可以返回的行)和不宽容的方法(抛出异常)。我倾向于采用“宽容”的方法,因为使用“宽容”方法,用户不会知道你没有返回所有存在的行——只是返回了错误发生前得到的所有行。但宽容的态度可能是有道理的。

    回答。首先,这不是所写方法中发生的事情。它将返回一个空的HashTable(这就是“null对象”的意思)。其次,在“未找到结果”的情况下,null并不总是答案。

    我看到了null,但我也看到了一个空的结果变量。我声称这两种方法都是正确的,但我更喜欢空结果变量。然而,最好保持一致,所以选择一种返回“无结果”的方法并坚持下去。

    5.我注意到有人和一群人说,应该把应用程序分成几层或几层。

    如果不查看应用程序的其余部分,这比其他问题更难回答。

        3
  •  4
  •   Esko    16 年前

    Null Object Pattern 是一种设计模式,你 总是 null Hashtable<Long, Dogs> 相反。

    原因是,由于它是一个集合,而您的其他代码将以此方式访问它,因此如果您返回一个空集合,它就不会崩溃;它不会被迭代,它不会包含任何令人惊讶的内容,它不会导致抛出NPE:s等等。

    确切地说,空对象是类/接口的一种特殊实现,它完全不做任何事情,因此没有任何副作用。因为它不存在的本质 使用它会使你的代码更清晰,因为当你知道你总是会从方法调用中得到一个对象时 singletons 只是躺着,这样做可以节省内存。

        4
  •  3
  •   Jesper    16 年前

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

    这使得你的代码容易受到众所周知的安全攻击, SQL injection PreparedStatement set...() 价值观 名字 正如你所做的那样。例子:

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

    如果你使用 预处理语句 ,JDBC驱动程序将自动处理转义中可能存在的某些字符 colValue

        5
  •  2
  •   Nerdfest    16 年前

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

        6
  •  0
  •   Dónal    16 年前

    通过使用 Spring-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. 始终如一地处理异常

        String sql = 
            "SELECT * FROM dogs_table " +
            "WHERE " + "colName" + " = '" + colValue + "'";
    
    推荐文章