我想多次使用相同的值。
如果我在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);
我有一个例外
SQL异常:SQL语法中有错误;检查手册 对应于您的MySQL服务器版本,以获得正确的语法 在'INSERT INTO test_table(TID,CREATED,OWNER,TITLE)值附近使用 (@ v1,@ v2,@ v3,@ v4)ON'在第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"));
但它看起来很难看。
有没有办法解决这个问题?
答案 0 :(得分:1)
一种选择是使用特殊的 VALUES()
函数来引用插入到列中的值,如果INSERT成功的话,就像这样:
...
ON DUPLICATE KEY
UPDATE CREATED = VALUES(CREATED)
, OWNER = VALUES(ONWER)
, TITLE = VALUES(TITLE)
首选示例中的后一种形式,使用占位符作为绑定变量。什么是丑陋的,必须两次提供相同的价值。
我建议这样的事情:
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; --"
使用预准备语句(使用带有占位符的静态SQL文本作为绑定变量,如上例所示)可以防止这种SQL注入模式。并且在一次执行中不允许多个语句是另一种阻止SQL注入攻击的方法。
答案 1 :(得分:0)
我认为@变量仅用于存储过程...
您可以定义存储过程,也可以使用第二个选项:
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"));