0

我有一个维护用户数据的 bean 类:

所以我已经创建了一个这样的 postgresql DB 表:

StringBuffer sqlStr = new StringBuffer();
sqlStr.append("CREATE TABLE Users ("
        user_id         bigint,
        username        character varying NOT NULL,
        biography       character varying NOT NULL
);

&我想创建一个查询命令并将我的字符串数据注入其中:

    sqlStr.append("INSERT INTO users(" +
            "user_id, username, biography)" +
            "\n\tVALUES (" + user.getID()+ "," + user.getUsername() + "," + user.getBiography()+");";

我的问题是,例如,如果来自我的方法的数据有引号或双引号或“,”假设用户传记是这样的,我的命令将出错:

您好,我是 X 先生,是一名“IT 专业人士”...

如果我运行我的应用程序并将输出保存在一个名为 query.sql 的文件中,我将无法使用它,因为我的查询命令由于引号和双引号而出错,如下所示:

INSERT INTO users(userid, username, biography)
     VALUES(2, 'Mehdi', 'hello, I'm Mr X an "IT Pro" ..');

我该如何解决这个问题?

4

2 回答 2

2

永远不应该使用上述方法来构建 SQL 查询。

“为什么不?” 你问,好吧;从哪儿开始。经典的例子是Bobby Tables,更普遍的问题是SQL 注入。这使您的程序容易受到攻击,但也容易受到随机故障 - 就像您描述的情况一样。

现在,解决方案。始终用于PreparedStatement构造您的查询。在你的例子中

final String query = "INSERT INTO users(user_id, username, biography) VALUES (?,?,?)";
final PreparedStatement ps = con.prepareStatement(query);
ps.setInt(1, user.getID());
ps.setString(2, user.getUsername());
ps.setString(3, user.getBiography());
ps.executeUpdate();

一个更好用的语法是SET语法而不是传统VALUES语法。然后查询看起来像

final String query = "INSERT INTO users SET user_id = ?, username = ?, biography = ?";

编辑

OP 正在为脚本文件构建查询,而不是在代码中执行查询。

Apache Commons Lang 中有一个实用程序类,StringEscapeUtils. 这有一个escapeSql方法。查看源代码,所有这些都是用另一个单引号转义单引号。

如果您使用单引号构建查询,则此方法有效:

VALUES (" + user.getID()+ ",'" + user.getUsername() + "'...

因此,一旦插入示例值,查询将从:

VALUES (10 ,'hello, I'm Mr X an "IT Pro"'...

会变成

VALUES (10 ,'hello, I''m Mr X an "IT Pro"'...

“我是”中的撇号现在已被转义且无害。

请注意,您显然需要转义值而不是查询,因此(假设您有static该类的导入)

VALUES (" + user.getID()+ ",'" + escapeSql(user.getUsername()) + "'...

但不会转义其他 sql 字符,例如百分号。

这确实是一种权宜之计,可以在您提出更强大的解决方案时使代码正常工作。你应该想出一个更强大的解决方案。

于 2013-04-13T12:49:03.777 回答
0

你为什么不使用PreparedStatement?这也将为您提供更好的性能,因为 SQL 将在 DB 端进行预编译。

或者

您可以使用 String.replaceAll http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#replaceAll(java.lang.String , java.lang.String)转义引号

于 2013-04-13T12:47:30.280 回答