我已经为mySQL编写了通用的DAO层(它可以使用Reflection和ResultSetMetaData保存\获取任何将Entity扩展到表的类对象)。我的实现在sql查询中几乎没有连接。它是否浪费了预备语句的所有优点,或者我只是松散地连接字符串而没有其他功能?
例如,用于删除实体的代码:
PreparedStatement prepStatement = con.prepareStatement("DELETE FROM "
+ tableName + " WHERE id = ?");
prepStatement.setLong(1, id);
答案 0 :(得分:3)
PreparedStatement
的主要好处是当代码的行为方式与此伪代码类似:
PreparedStatement ps = con.prepareStatement("blabalblabla");
for (int i = 0; i < a gazillion times; i++) {
// Set parameters into ps
...
// execute already prepared statement
ps.execute();
}
也就是说,您准备一次并多次执行 ,每次都使用不同的参数集。这允许驱动程序/数据库仅执行一次可能代价高昂的操作(例如解析),然后重用该工作。除此之外,使用PreparedStatement
可能会被解释为驱动程序的提示,它应该缓存该语句资源或其他东西,因为它将在以后使用,但我不认为它会产生如此大的影响。 “准备一次执行许多”的方法。
使用串联添加表名不会禁用JDBC驱动程序执行的优化(如果有)。但无论如何,如果你的代码更多地“准备一次执行一次”而不是“准备一次执行多次”,那么PreparedStatement可能只有一点性能优势。
请注意,以上所有内容都是高度依赖数据库/驱动程序的。例如,如果您按照我所描述的“准备一次执行多次”的方式使用PreparedStatement
,Oracle会更好地执行很多。作为最后一条建议,请不要忘记,除非您没有其他选择,否则应避免连接参数值,因为性能和安全原因。
答案 1 :(得分:1)
建议使用准备好的语句来提高数据库性能。 理论上,DB驱动程序缓存预准备语句(您可能需要在连接对象上启用缓存)。 我认为连接不是那么重要。 请记住,tableName在驱动程序缓存中可能区分大小写。
我会检查您的数据库驱动程序功能,您应该能够调试驱动程序,并监视数据库以查看语句的处理/执行方式。
答案 2 :(得分:0)
示例中的变量tableName可能会引入SQL注入的漏洞,但它可能是防止这种情况的替代方法。例如,
Map<String,String> myTables; // key and value are the same.
tableName = myTables.get(tableName); // safe known value or null.
通常,最好只是始终使用预先准备好的语句以避免麻烦。但是,有时构建查询(通常是where
查询)“动态”可以保存许多行,否则接近重复代码,因此很难说“永远不会这样做”。