Java 使用准备好的语句设置表名
我试图使用prepared语句设置表名以从中选择数据,但在执行查询时不断出现错误 错误和示例代码如下所示Java 使用准备好的语句设置表名,java,sql,prepared-statement,Java,Sql,Prepared Statement,我试图使用prepared语句设置表名以从中选择数据,但在执行查询时不断出现错误 错误和示例代码如下所示 [Microsoft][ODBC Microsoft Access Driver] Parameter 'Pa_RaM000' specified where a table name is required. private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [?]"; //?=date publ
[Microsoft][ODBC Microsoft Access Driver] Parameter 'Pa_RaM000' specified where a table name is required.
private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [?]"; //?=date
public Execute(String reportDate){
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection(Display.DB_MERC);
PreparedStatement st = conn.prepareStatement(query1);
st.setString(1, reportDate);
ResultSet rs = st.executeQuery();
您是否知道是什么原因导致了这种情况?不能将表名用作参数。它必须是硬编码的。因此,您可以执行以下操作:
private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [" + reportDate + "?]";
表名不能用作参数。它必须是硬编码的。因此,您可以执行以下操作:
private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [" + reportDate + "?]";
我不确定是否可以使用PreparedStatement来指定表的名称,只指定某些字段的值。无论如何,您可以尝试相同的查询,但不带括号:
"SELECT plantID, edrman, plant, vaxnode FROM ?"
我不确定是否可以使用PreparedStatement来指定表的名称,只指定某些字段的值。无论如何,您可以尝试相同的查询,但不带括号:
"SELECT plantID, edrman, plant, vaxnode FROM ?"
正如许多人所说,不能将语句参数用于表名,只能将变量作为条件的一部分 基于您有一个包含(至少)两个表名的变量表名这一事实,最好创建一个方法,该方法接受您存储的实体并返回一个准备好的语句
PreparedStatement p = createStatement(table);
正如许多人所说,不能将语句参数用于表名,只能将变量作为条件的一部分 基于您有一个包含(至少)两个表名的变量表名这一事实,最好创建一个方法,该方法接受您存储的实体并返回一个准备好的语句
PreparedStatement p = createStatement(table);
这在技术上是可行的,但实际上非常糟糕
String sql = "IF ? = 99\n";
sql += "SELECT * FROM first_table\n";
sql += "ELSE\n";
sql += "SELECT * FROM second_table";
PreparedStatement ps = con.prepareStatement(sql);
然后,当您要从第一个_表中选择时,可以使用
ps.setInt(1, 99);
或者,如果没有,您可以将其设置为其他内容。这在技术上是可行的,但实践非常糟糕
String sql = "IF ? = 99\n";
sql += "SELECT * FROM first_table\n";
sql += "ELSE\n";
sql += "SELECT * FROM second_table";
PreparedStatement ps = con.prepareStatement(sql);
然后,当您要从第一个_表中选择时,可以使用
ps.setInt(1, 99);
否则,您可以将其设置为其他设置。这可能会有帮助:
public ResultSet getSomething(String tableName) {
PreparedStatement ps = conn.prepareStatement("select * from \`"+tableName+"\`");
ResultSet rs = ps.executeQuery();
}
这可能有助于:
public ResultSet getSomething(String tableName) {
PreparedStatement ps = conn.prepareStatement("select * from \`"+tableName+"\`");
ResultSet rs = ps.executeQuery();
}
如果需要一个不易受SQL注入攻击的解决方案,则必须为所有需要的表复制查询:
final static String QUERIES = {
"SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ...",
"SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ...",
"SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ...",
...
};
是:查询是重复的,只有表名不同
现在您只需选择适合表的查询,例如
...
PreparedStatement st = conn.prepareStatement(QUERIES[index]);
...
您可以使用JPA、Hibernate之类的方法
如果你想要一个更冗长的方法考虑使用EnUM,比如
enum AQuery {
Table1("SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ..."),
Table2("SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ..."),
Table3("SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ..."),
...
private final String query;
AQuery(final String query) {
this.query = query;
}
public String getQuery() {
return query;
}
}
现在使用索引或索引
String sql = AQuery.values()[index].getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...
或者使用表名
String sql = AQuery.valueOf("Table1").getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...
如果需要一个不易受SQL注入攻击的解决方案,则必须为所有需要的表复制查询:
final static String QUERIES = {
"SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ...",
"SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ...",
"SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ...",
...
};
是:查询是重复的,只有表名不同
现在您只需选择适合表的查询,例如
...
PreparedStatement st = conn.prepareStatement(QUERIES[index]);
...
您可以使用JPA、Hibernate之类的方法
如果你想要一个更冗长的方法考虑使用EnUM,比如
enum AQuery {
Table1("SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ..."),
Table2("SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ..."),
Table3("SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ..."),
...
private final String query;
AQuery(final String query) {
this.query = query;
}
public String getQuery() {
return query;
}
}
现在使用索引或索引
String sql = AQuery.values()[index].getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...
或者使用表名
String sql = AQuery.valueOf("Table1").getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...
在查询中,您需要用括号来转义“/”,或者可能是日期。我去年夏天查过了,在查询中需要括号来转义“/”,或者可能是日期。我去年夏天查过了是的,输入净化是为了防止SQL注入!如果需要将不同的表名替换为具有相同结构的查询,则表明数据库设计中存在缺陷。至少它指向具有相同关系属性的多个表。将其规范化为一个带有“subject”列的表。是的,输入清理以防止SQL注入!如果需要将不同的表名替换为具有相同结构的查询,则表明数据库设计中存在缺陷。至少它指向具有相同关系属性的多个表。将其规范化为一个带有“主题”列的表。您能否为您的答案提供一些上下文,这样未来的读者就可以了解如何将其应用于他们的问题,而不仅仅是在这种情况下。易受SQL注入的影响。不要这样做!您能否为您的答案提供一些上下文,这样未来的读者就可以了解如何将其应用于他们的问题,而不仅仅是在这种情况下。易受SQL注入攻击。不要这样做!不!这是由于表名上的SQL-injection.use
org.apache.commons.lang.StringEscapeUtils.escapeSql
导致的安全问题,以确保您不会将架构置于风险中。@所有建议表名的字符串串联的人:不要这样做。这让位于SQL注入——OWASPs Top 10中的头号攻击(请参阅)不言而喻,如果要这样做,那么必须将表名列入白名单(并且您应该使用白名单中的值,而不是输入的值,只是为了确保;regex等)不要使用org.apache.commons.lang.StringEscapeUtils.escapeSql
。它在commons.lang3中被弃用,并且在任何情况下都只能用双单引号替换单引号。它不会阻止SQL注入。看,别!这是由于表名上的SQL-injection.useorg.apache.commons.lang.StringEscapeUtils.escapeSql
导致的安全问题,以确保您不会将架构置于风险中。@所有建议表名的字符串串联的人:不要这样做。这让位于SQL注入——OWASPs Top 10中的头号攻击(请参阅)不言而喻,如果要这样做,那么必须将表名列入白名单(并且您应该使用白名单中的值,而不是输入的值,只是为了确保;regex等)不要使用org.apache.commons.lang.StringEscapeUtils.escapeSql
。它在commons.lang3中被弃用,并且在任何情况下都只能用双单引号替换单引号。它不会阻止SQL注入。见和。