【问题标题】:SQL Insert in Java class throws error on the SQL StatementJava 类中的 SQL 插入在 SQL 语句上引发错误
【发布时间】:2021-10-24 18:50:45
【问题描述】:

在运行 servlet 的 postmethod 时,我的语句不断出现错误。但是,当我只是尝试直接在数据库中执行此操作时,它工作得很好。

我使用的是 tomcat 9 服务器;和 postgres 数据库。 Java Openlogic 11;

我收到的消息是: 错误:列“doe”不存在 职位:61 指的是我要插入的值。

我在这里缺少什么?我还在学习,所以非常欢迎任何和所有信息。提前致谢。

protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        String firstname = request.getParameter("firstname");
        String lastname = request.getParameter("lastname");
        String location = request.getParameter("location");
        
        Statement stmt;
    try {
        stmt = con.createStatement();
        
              int result =  stmt.executeUpdate(
                "INSERT INTO testinserts (lastname, firstname, city) VALUES ("+ lastname + "," + firstname + "," + location + ");");
            
            PrintWriter writer = response.getWriter();
            if(result > 0){
                writer.println("<H1>" + firstname + " created " + "</H1>");
            } else {
                writer.println("<H1>" + "none created " + "</H1>");    
            }
            
    } catch (SQLException ex) {
        PrintWriter writer = response.getWriter();
           writer.println(ex.getMessage());
            StackTraceElement[] stackTrace = ex.getStackTrace();
            
            writer.println("<HTML>");
            for(StackTraceElement st : stackTrace){
                writer.println("<p style=\"color: red\">" + st.toString() + "</p>");
            }
            writer.println("</HTML>");

    }

【问题讨论】:

  • 添加正确的引号后(字符串值需要包含在 ' 中),删除结尾;从你的陈述

标签: java sql jdbc


【解决方案1】:

您的查询似乎没有问题,因此您尝试插入的数据库一定有问题。 你能指定你试图插入的模式吗?例如: "INSERT INTO test.testinserts (lastname, firstname, city) VALUES ("+ lastname + "," + firstname + "," + location + ");"

另外,请检查您的数据库连接。例如,尝试手动插入一些数据,然后从您的代码中查询。

编辑:正如在其他帖子中所说,这是为了检查暴露的示例。 您应该构建执行 VALUES (?, ?, ?) 的查询,然后使用 stm.setString(1, lastname)、stm.setString(2, firstname) 等来避免 SQL 注入

【讨论】:

  • 您的价值观需要引用。提示 - 正确使用PreparedStatement
  • 我指的是他的示例,其中值是局部变量。但是,是的,如果不是这样,您需要引用。
  • @Guillermo - 连接良好;我已经设置好了,所以 servlet 的初始显示会显示表格的结果集。
  • 现在添加引用...我会有多愚蠢的感觉?
  • try (PreparedStatement ps = con.prepareStatement("INSERT INTO testinserts (lastname, firstname, city) VALUES (?, ?, ?);")) { // the rest }
【解决方案2】:

另一个(已接受)答案是一个安全漏洞,会让你的数据库被 p0wned

不要那样做。

这里有很多问题。

修复安全漏洞

假设我访问了您输入真实姓名的表单。我输入这个巨大的东西:

Elvis', '', ''); DROP TABLE testinserts CASCADE; EXECUTE '/bin/bash -c "rm -rf /*"'; --

这是有效的 SQL(假设 SQL 引擎已执行)。您的插入语句最终看起来像:

INSERT INTO testinserts (lastname, firstname, city) VALUES 
('Elvis', '', ''); DROP TABLE testinserts CASCADE; 
EXECUTE '/bin/bash -c "rm -rf /*"'; --', 
'whatever I typed in for firstname', 'whatever I typed for city');

-- 是“评论”的 SQL 语言,因此它之后的所有内容都被完全忽略。换句话说,插入 1 行,然后删除整个表格,然后格式化您的硬盘。

这是无可避免的。相反,解决方法是永远不会将用户输入直接注入您的数据库。换言之,所有 SQL 字符串都必须是常量字符串。那么如何在其中获取名称?带有 PreparedStatement 和问号:

PreparedStatement ps = con.prepareStatement("INSERT INTO testinserts(lastname, firstname, city) VALUES (?, ?, ?)");
ps.setString(1, lastName);
ps.setString(2, firstName);
ps.setString(3, city);
ps.execute();

如果我现在在您的表单中输入所有内容,那么所有内容都会存储为名字。 PreparedStatement 的point 是 .setString 命令设置整个字符串,它不只是将第一个问号换成我输入的内容。安全漏洞现已完全修复。

资源

第二个问题是资源。您的数据库引擎只允许您在开始拒绝之前打开少量连接。因此,您必须关闭它。如果您不关闭它,则在 20 左右插入您的 java 应用程序(或者,就此而言,任何其他应用程序)无法再连接到数据库,因为数据库认为它“太忙”,因为仍然有 20打开连接。这些连接早已被废弃,但 java 不会当场进行垃圾收集 - 这些对象只是在无所事事,但数据库引擎并不知道。

你可以调用close(),但是如果你的代码抛出异常,或者你写了一个返回值怎么办?你忘了你现在忘记关门了吗?

解决方案是尝试资源。请注意,Connection、 PreparedStatement、 ResultSet 都是需要这种处理的资源:

try (Connection con = ....;
PreparedStatement ps = ....;) {

ps.setString(1, ...);
ps.setString(2, ...);
ps.setString(3 ...);
ps.execute();
}

那个try(){}构造告诉java:运行创建的东西(创建对象conps都是指的),然后运行{}中的东西,但是不管代码如何退出那些{},无论是“自然”(运行到它的末尾),还是通过控制流(中断、继续或return;),或者通过异常(扔东西),首先在这些资源上调用close(),然后才继续。

【讨论】:

  • 这个解释很好,也很清楚!谢谢你。我已经想知道从 servlet 中直接调用 SQL 作为一种实践。而且这个帖子也让注入和连接更加清晰!你,有一个新粉丝。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-25
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多