我想多次使用相同的值。
如果我在dbForge
中使用MySQL下一个查询,
SET @v1 = 123, @v2='2014-04-11', @v3 = 'user1', @v4='title1';
INSERT INTO test_table (TID, CREATED, OWNER, TITLE)
VALUES (@v1,@v2,@v3,@v4)
ON DUPLICATE KEY UPDATE
CREATED=@v2, OWNER=@v3, TITLE=@v4
它正确执行,但是在Java中,当我使用代码
final String dbQuerry = "SET @v1 = %s, @v2='%s', @v3 = '%s', @v4='%s';\n"+
"INSERT INTO test_table (TID, CREATED, OWNER, TITLE)\n" +
"VALUES (@v1,@v2,@v3,@v4)\n" +
"ON DUPLICATE KEY UPDATE\n" +
"CREATED=@v2, OWNER=@v3, TITLE=@v4";
String currentQuerry = String.format(dbQuerry, t.getParam("ID"),
t.getParam("Date"),
t.getParam("User"),
t.getParam("Title"));
mDBStatement.execute(currentQuerry);
我有一个异常(exception)
SQL Exception: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO test_table (TID, CREATED, OWNER, TITLE) VALUES (@v1,@v2,@v3,@v4) ON ' at line 2
我可以使用这样的东西
final String dbQuerry = "INSERT INTO test_table (TID, CREATED, OWNER, TITLE)\n" +
"VALUES (?,?,?,?)\n" +
"ON DUPLICATE KEY UPDATE\n" +
"CREATED=?, OWNER=?, TITLE=?";
PreparedStatement st = mDBConnection.prepareStatement(dbQuerry);
st.setInt(1, Integer.valueOf(t.getParam("ID")));
st.setString(2, t.getParam("Date"));
st.setString(5, t.getParam("Date"));
st.setString(3, t.getParam("User"));
st.setString(6, t.getParam("User"));
st.setString(4, t.getParam("Title"));
st.setString(7, t.getParam("Title"));
但是看起来很丑。
有办法解决这个问题吗?
最佳答案
一种选择是使用特殊的 VALUES()
函数来引用将插入到列中的值(如果 INSERT 成功),如下所示:
...
ON DUPLICATE KEY
UPDATE CREATED = VALUES(CREATED)
, OWNER = VALUES(ONWER)
, TITLE = VALUES(TITLE)
<小时/>
您的示例中的后一种形式是首选,使用占位符作为绑定(bind)变量。丑陋的是必须两次提供相同的值。
我推荐这样的东西:
final String dbQuerry = "INSERT INTO test_table (TID,CREATED,OWNER,TITLE)\n" +
" VALUES (?,?,?, ?)\n" +
" ON DUPLICATE KEY UPDATE\n" +
" CREATED=VALUES(CREATED), OWNER=VALUES(OWNER), TITLE=VALUES(TITLE)";
PreparedStatement st = mDBConnection.prepareStatement(dbQuerry);
st.setInt(1, Integer.valueOf(t.getParam("ID")));
st.setString(2, t.getParam("Date"));
st.setString(3, t.getParam("User"));
st.setString(4, t.getParam("Title"));
这并不难看。这就是规范模式。
<小时/>如果我们要更新插入多行(例如使用 VALUES 子句),则使用特殊的 VALUES()
函数特别有用
INSERT INTO fee (fi, fo, fum)
VALUES
(1,'doo','dah'),(2,'menom','menah'),(3,'buhdeep','uhdeepee')
ON DUPLICATE KEY
UPDATE fo = VALUES(fo)
, fum = VALUES(fum)
或者,使用 INSERT ... SELECT 表单:
INSERT INTO fee (fi, fo, fum)
SELECT t.ay, t.bee, t.cee FROM sometable t
ON DUPLICATE KEY
UPDATE fo = VALUES(fo)
, fum = VALUES(fum)
<小时/>
顺便说一句...如果连接字符串中不包含 allowMultiQueries=true
,从第一个表单返回的错误就是我们预期的错误类型。请注意,每次执行启用多个查询实际上会禁用安全功能。
仔细考虑将生成并发送到数据库的 SQL 文本以及一些精心设计的值:
val = "foo'; DROP TABLE students; --"
使用准备好的语句(使用带有绑定(bind)变量占位符的静态 SQL 文本,如上例所示)可以防止这种 SQL 注入(inject)模式。禁止一次执行多个语句是阻止 SQL 注入(inject)攻击的另一种方法。
关于java - Java 查询中的 SQL 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23064017/