java - Java 查询中的 SQL 变量

标签 java mysql jdbc

我想多次使用相同的值。

如果我在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/

相关文章:

java - Citrix Xenapp 6.5 下 Java 中的当前日期/时间

javascript - 如何在 PHP 中使用 javascript 函数在单击按钮时执行 sql 删除查询

mysql - Django 脚本运行每次迁移

mysql - 用另一个表中的数据替换 MySQL 表中的数据

java - 如何防止JSP中的SQL注入(inject)?

java - 查询从 Access 中的多个表中删除

Java:允许重复的排序集合,内存效率高并提供快速插入+更新

java - 如何比较 RGB 值与颜色?

java - 找不到适合 jdbc :oracle:thin:@localhost:1522:xe 的驱动程序

postgresql - Spark SQL - PostgreSQL JDBC 类路径问题