如何为java准备好的语句插入使用表名变量[重复]

Posted

技术标签:

【中文标题】如何为java准备好的语句插入使用表名变量[重复]【英文标题】:How to use a tablename variable for a java prepared statement insert [duplicate] 【发布时间】:2012-07-03 22:59:58 【问题描述】:

我正在使用 java PreparedStatment 对象来构造一系列批处理的 INSERT 查询。查询语句的格式...

String strQuery = "INSERT INTO ? (col1, col2, col3, col4, col5) VALUES (?,?,?,?,?,?);";

...所以字段值和表名都是变量(即,我有多个具有相同列格式的表,每个插入将被定向到不同的表)。如果我删除“?”,我可以让执行工作。 tablename 变量和硬代码,但每个准备好的语句都将插入到不同的表中,因此需要保留一个变量,我在执行批处理查询之前使用...

stmt.setString(1, "tableName1");

请问我怎样才能让它成为一个动态变量?

【问题讨论】:

【参考方案1】:

你不能。您需要使用 String.format 使用字符串连接/占位符来构造 sql。准备好的语句用于列值而不是表名。

【讨论】:

谢谢大家...似乎我不知道要插入的表名,直到交换每行的变量,最好的办法是在数据库中构造插入存储过程。然后将每一行的所有参数传递到存储过程中,然后让数据库处理表名操作。不过还是谢谢大家的回复。 :-) 这是否意味着动态表名无法实现 SQL 注入保护? @Richard 我得出了同样的结论,这听起来很傻,但至少根据数据库中可用表的列表检查表名相当容易。 @RichardTingle 不是不可能,只是更难。例如,在 mysql 中,您可以将表名括在反引号中,并使用双反引号转义反引号:dev.mysql.com/doc/refman/5.7/en/identifiers.html 每个人都在谈论 SQL 注入。但我很难想象可能会提示用户输入表名。如果您在多个表上运行相同的查询,则表名作为参数仅在应用程序代码中创建和传递。【参考方案2】:

您可以使用占位符代替表名,然后将其替换为您的表名。

String strQuery = "INSERT INTO $tableName (col1, col2, col3, col4, col5)
                   VALUES (?,?,?,?,?,?);";

当你知道表名时替换

String query =strQuery.replace("$tableName",tableName);
stmt =conn.prepareStatement(query);

【讨论】:

易受 SQL 注入攻击。孩子们,不要使用这个答案! 仅当 $tablename 取自用户输入时,对吧?但是,如果像单选按钮选择这样的东西返回一个枚举值,或者任何其他将 $tablename 的可能值限制为定义的集合的方法,那会很好吗? @SigmaX 那么你的解决方案是什么,不易受到 SQL 注入攻击? @Mahdi 第一个目标应该是完全避免使用动态 SQL 查询。但如果必须,我会从服务器检索现有表的列表并将其用作白名单来检查 tableName 是否是有效现有表的名称。 这完全取决于 myTablename 的来源。请参阅上面 Jonathan Warner 的评论【参考方案3】:

另一种选择是String.format:

例如

String sql = String.format("INSERT INTO $1%s (col1, col2, col3, (etc)",  myTablename);

【讨论】:

这是常见的“哦,我知道什么是 SQL 注入”的偏执狂——这完全取决于 myTablename 的来源。 同意。但是,与大多数安全问题一样,问答网站的大部分访问者不会明白他们需要注意 myTablename 的来源。所以答案需要限定。 没错,您可以在原始评论中提出这一点,而不是大写字母 8=【参考方案4】:

如果您的表名仅来自您自己的代码...

...您需要将其添加到原始字符串中:

String tableName = "some_table_name";
// some other code
String strQuery = "INSERT INTO " + tableName + " (col1, col2, col3, col4, col5) VALUES (?,?,?,?,?,?);";

如果表名来自任何其他不可靠的来源(用户输入,其他代码传入的参数),请不要这样做并查看其他答案!

【讨论】:

易受 SQL 注入攻击。孩子们,不要使用这个答案! ...这取决于您的 tableName 来自哪里。如果它来自用户或来自不可靠的客户,那么我同意你的看法。但如果它包含在您自己的方法中,那么 String 的不变性意味着它肯定是安全的。 技术上是正确的。但是一个好的答案仍然需要一个大的免责声明:“作为一项规则,避免使用动态 SQL 查询,句号——它被广泛认为是不安全的做法。如果你必须这样做,请确保你确切地知道你在做什么。”

以上是关于如何为java准备好的语句插入使用表名变量[重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用 PDO 准备好的语句插入致命错误 [重复]

如何为sql插入命令传入变量[重复]

插入带有准备好的语句的日期时间[重复]

向数据库插入的数据不重复,如何用Java做验证

我可以在准备好的语句中参数化表名吗?

我可以在准备好的语句中参数化表名吗?