我有一个bean类来维护用户数据:
soppose我已经创建了一个这样的postgresql数据库表:
StringBuffer sqlStr = new StringBuffer();
sqlStr.append("CREATE TABLE Users ("
user_id bigint,
username character varying NOT NULL,
biography character varying NOT NULL
);
&安培;我想创建一个查询命令并在其中注入我的String数据:
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" ..');
我该如何解决这个问题?
答案 0 :(得分:2)
您应该从不使用上述方法构建SQL查询。
“为什么不呢?”你问,好吧;从哪儿开始。典型的例子是Bobby Tables,更普遍的问题是SQL injection。这会使您的程序受到攻击,但也会随机失败 - 就像您描述的情况一样。
现在,解决方案。始终使用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字符,例如百分号。
在您提出更强大的解决方案时,这实际上是一种能够使代码工作的权宜之计。你应该提出一个更强大的解决方案。
答案 1 :(得分:0)
为什么不使用 PreparedStatement ?这也将为您提供更好的性能,因为SQL将在数据库端进行预编译。
或
您可以使用转义引号 String.replaceAll http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#replaceAll(java.lang.String,java.lang.String)