这是另一个有争议的主题,但这一次我只搜索简单而有记录的答案。场景:
我们假设以下方法:
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,或者将生成异常,如下所示:
String str = null; 的System.out.println(str.toString());
3。如果在从ResultSet的当前行初始化dog对象时发生了一些不好的事情,例如:连接失败,不兼容的值已经传递给dog属性设置器等等,该怎么办?我现在可能在哈希表中有10个元素,或者没有(第一行)。下一步操作是什么:a)返回空哈希表; b)返回结果哈希表,它在这个阶段的方式; c)抛出异常:这里的异常类型是什么?
4。我想你们都会同意这一点:没有什么不好的事情发生,审讯中没有行,空值就会返回。但是,@ThorbjørnRavnAndersen说here我应该返回一个NullObject而不是null值。我不知道那是什么。
5。我注意到人们和一群人说应该将应用程序拆分成层或某种层次。考虑到上面的例子,这里有哪些层,除了我能想到的这些层:
Layer1 :: Database层,执行操作:此方法。
Layer2 :: ??? :构建新Dog对象的一些层:我的Dog对象。
Layer3 ::? :我打算用狗的集合做一些事情的层:主要是GUI层,或用户界面的子层。
在应用程序流程之后,如果在第一层中发生异常,最好的想法是什么?我的想法:捕获异常,记录异常,返回一些值。这是最好的做法吗?
Manny感谢您的回答,我期待着看到其他人对这些问题的看法。
答案 0 :(得分:8)
我会避免以下
sql.append("SELECT * FROM ").append("dogs_table");
sql.append(" WHERE ").append(colName).append("='");
sql.append(colValue).append("'");
而是使用PreparedStatement及其关联的参数设置方法(setString()
)等。这将防止colValue
的值出现问题和SQL注入攻击(或更普遍) ,colValue
形成一些SQL语法)。
如果集合只是空的话,我会从不返回null。这看起来非常违反直觉,而且从客户的角度来看完全出乎意料。
我不建议在错误条件下返回null,因为您的客户端必须明确检查这个(并且可能会忘记)。如果需要,我会返回一个空集合(这可能类似于你的注释re。一个空对象),或者更可能抛出异常(取决于环境和严重性)。该例外是有用的,因为它将携带与遇到的错误有关的一些信息。 Null告诉你什么。
如果在构建Dog
对象时遇到问题,您应该怎么做?我认为这取决于您希望应用程序的强大和弹性。返回Dog
的子集是一个问题,还是完全是灾难性的,你需要报告这个?这是一个应用程序要求(我必须满足过去的任何一种情况 - 尽力而为或全有或全无)。
一些观察结果。我使用的是HashMap而不是旧Hashtable
(已同步进行所有访问,更重要的是,不是正确的Collection
- 如果您有Collection
,则可以通过出于类似原因,期望任何 Collection
)和StringBuilder超过StringBuffer
的任何其他方法。这不是一个重大问题,但值得了解。
答案 1 :(得分:5)
你问五个问题
实际上有几个。1。你有什么方法可以改善这种归还狗的技术,具有一些属性?
2。 rs.next()将为null ResultSet返回false,或者将生成异常
这似乎不是一个问题,但是,只要不再有任何要处理的行,rs.next()就会返回false。
3。如果在从ResultSet的当前行初始化dog对象时发生了一些不好的事情
,该怎么办?
如果“发生了不好的事情”,你接下来要做的就取决于你和你的设计。有宽容的方法(返回你可以的所有行)和不宽容(抛出异常)。我倾向于倾向于“无情”的方法,因为使用“宽容”的方法,用户不会知道你没有返回所有存在的行 - 只是你在错误之前得到的所有行。但是可能存在宽容方法的情况。
4。我想你们都会同意这一点:没有什么不好的事情发生,审讯中没有行,会返回空值。
这不是一个明显的正确的答案。首先,它不是所写方法中发生的事情。它将返回一个空的HashTable(这是“null对象”的意思)。其次,在“未找到结果”的情况下,null并不总是答案。
我见过null,但我也看到了一个空的结果变量。我声称它们都是正确的方法,但我更喜欢空的结果变量。但是,最好保持一致,所以选择一种返回“无结果”并坚持下去的方法。
5。我注意到人们和一群人说应该将应用程序分成几层或某种层次。
这比其他人更难回答,而没有看到你申请的其余部分。
答案 2 :(得分:4)
Null Object Pattern是一种设计模式,您始终返回一个对象以避免NPE:s和代码中的任何空检查。在您的情况下,这意味着不是返回null
,而是返回空Hashtable<Long, Dogs>
。
原因是因为它是一个集合而你的其他代码会这样访问它,所以如果你返回一个空集合它就不会分解;它不会被迭代,它不会包含任何令人惊讶的东西,它不会导致NPE:s被抛出等等。
确切地说,Null对象是类/接口的特殊实现,它绝对没有任何作用,因此没有任何类型的副作用。由于它不是null
使用它的性质会使你的代码更清晰,因为当你知道你总是会从你的方法调用获得一个对象,无论方法内部发生了什么你甚至不必检查空值,也不要让代码对它们作出反应!因为Null Object没有做任何事情,你甚至可以将它们放在singletons只是躺在那里,从而通过这样做来节省内存。
答案 3 :(得分:3)
不要像连接字符串一样构建SQL查询:
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();
如果使用PreparedStatement
,JDBC驱动程序将自动处理转义colValue
中可能存在的某些字符,以便SQL注入攻击不再起作用。
答案 4 :(得分:2)
如果发生错误,请抛出异常。如果没有数据,则返回空集合,而不是null。 (另外,通常你应该返回更通用的'Map',而不是具体的实现),
答案 5 :(得分:0)
通过使用Spring-JDBC而不是普通的JDBC,可以显着减少样板JDBC代码的数量。这是使用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);
}
Spring负责:
正如其他人所说,你真的应该使用PreparedStatement来构造SQL而不是String(或StringBuffer)。如果由于某种原因你无法做到这一点,你可以通过构建这样的SQL来提高查询的可读性:
String sql =
"SELECT * FROM dogs_table " +
"WHERE " + "colName" + " = '" + colValue + "'";