1

大家,早安 !我创建了一个带有一些单选按钮的 jsp 页面。现在,我正在接收用户对 servlet 内的数组中的那些单选按钮的响应。现在我想将这些数组项发送到我的 oracle 数据库表中。但我遇到了问题。jsp页面的代码是:

<%@page import="java.util.Calendar"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="TestAms" method="post">
<%
Calendar cal = Calendar.getInstance();
int md = cal.getActualMaximum(Calendar.DATE);
    for(int i = 0; i <= md; i++){
        %>
            <input type="radio" name="<%= i%>" value="<%=i %>">
        <%
    }
%>
<input type="submit" value="SUBMIT">
</form>
</body>
</html>

servlet 的代码是:

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestAms extends HttpServlet {

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    PrintWriter out = response.getWriter();

    Connection conn = null;
    PreparedStatement pstmt = null;

    Calendar cal = Calendar.getInstance();
    int md = cal.getActualMaximum(Calendar.DATE);
    int count =0;
    String s[] = new String[md+1];

    String jan = "JAN";
    String query;

    try {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE","urja","urja");

        for (int y=1; y<=md; y++){
            s[y] = request.getParameter(Integer.toString(y));
            out.println(s[y]);
            if( y  < md ){
                int z = y+1;
                out.println("db var : " + z);
                query = "UPDATE V_TEST SET \"" + z + "\" = ? WHERE V_MONTH = '"+ jan +"'";
                pstmt = conn.prepareStatement(query);
                pstmt.setString(z, s[y]);                   //getting error in this line as per the debug report.
                int i = pstmt.executeUpdate();
                out.println("inserted : " + i);
            }
        }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }       
    finally {
        if (conn != null) {
            try {
                conn.close();
                pstmt.close();
            }
            catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
}

我的表 sql 是:

CREATE TABLE  "V_TEST" 
(   "V_MONTH" VARCHAR2(4000) NOT NULL ENABLE, 
"1" VARCHAR2(4000), 
"2" VARCHAR2(4000), 
"3" VARCHAR2(4000), 
"4" VARCHAR2(4000), 
"5" VARCHAR2(4000), 
"6" VARCHAR2(4000), 
"7" VARCHAR2(4000), 
"8" VARCHAR2(4000), 
"9" VARCHAR2(4000), 
"10" VARCHAR2(4000), 
"11" VARCHAR2(4000), 
"12" VARCHAR2(4000), 
"13" VARCHAR2(4000), 
"14" VARCHAR2(4000), 
"15" VARCHAR2(4000), 
"16" VARCHAR2(4000), 
"17" VARCHAR2(4000), 
"18" VARCHAR2(4000), 
"19" VARCHAR2(4000), 
"20" VARCHAR2(4000), 
"21" VARCHAR2(4000), 
"22" VARCHAR2(4000), 
"23" VARCHAR2(4000), 
"24" VARCHAR2(4000), 
"25" VARCHAR2(4000), 
"26" VARCHAR2(4000), 
"27" VARCHAR2(4000), 
"28" VARCHAR2(4000), 
"29" VARCHAR2(4000), 
"30" VARCHAR2(4000), 
"31" VARCHAR2(4000)
);

我得到的完整错误是:

java.sql.SQLException: Missing IN or OUT parameter at index:: 1
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179)
at oracle.jdbc.driver.OracleStatement.checkBindsInAndOut(OracleStatement.java:1876)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2638)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:589)
at TestAms.doPost(TestAms.java:47)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:931)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

我的数据库看起来像这样

我想在每一列中存储日期(已检查 jsp 页面中的单选按钮的日期)。

这是我的jsp页面。 jsp页面

提前致谢。

4

1 回答 1

1

老实说,你在这里做错了很多。

首先,使用参数化 SQL。使用 PreparedStatements。 除非绝对必须,否则不要使用连接来构建 SQL 字符串,否则你会发现自己成为 SQL 注入攻击的受害者。这些天在讨论 SQL 注入时,这是强制性的,这里是关于 SQL 注入的 xkcd 漫画的链接:http ://www.xkcd.com/327 。

其次,您收到 ORA-00927 错误,因为您发送到数据库的 SQL 语句无效。我不知道方括号在 Oracle SQL 中的任何地方都有效(字符串和双引号标识符之外)。 s[md]可能有一个 Java 表达式的值,但在字符串中它不会被评估,因此要求数据库执行一个UPDATE V_TEST SET s[md]= ...它不理解的查询。

Oracle 知道 SQL 语句应该是以下形式

UPDATE table SET column = value ....

通过您的查询,它一直UPDATE V_TEST SET s以为s是列的名称,然后它感到惊讶,因为它[在想要 a 时找到了 a =

此外,您的列名是数字,因此它们需要用双引号括起来,否则 Oracle 会认为您正在尝试为数字分配值。 UPDATE V_TEST SET 1 = 'xyz'不是有效的 SQL,UPDATE V_TEST SET "1" = 'xyz'是。

而不是写作,

    stmt = conn.createStatement();
    //Query is not right
    int i = stmt.executeUpdate("UPDATE V_TEST SET s[md] = '"+s[md]+"' WHERE V_MONTH = '"+jan+"'");

    // Use \" to escape the double-quotes, so that the query ends up like
    // UPDATE V_TEST SET "30" = ? WHERE V_MONTH = ?
    // In this case we have to use string concatenation to build up the query,
    // but we're only inserting an integer so this won't be a problem.
    String sql = "UPDATE V_TEST SET \"" + md + "\" = ? WHERE V_MONTH = ?";

    // stmt will need to be declared as a PreparedStatement, not a Statement.
    stmt = conn.prepareStatement(sql);

    // Set the values for the two '?' placeholders.
    stmt.setString(1, s[md]);
    stmt.setString(2, jan);

    int i = stmt.executeUpdate();

这应该可以解决您的前两个问题。

第三,您似乎没有关闭连接,因为您没有关闭连接(除非您的查询成功,他们目前没有这样做)。您应该在finally块中关闭它们,因为这样可以确保即使在抛出异常的情况下它们也被关闭。

您应该执行以下操作(这是一个草图):

    Connection conn = null;
    try {
        // get database connection ...

        // do stuff with connection ...
    }
    catch (SQLException e) {
        // handle error connecting to the database or using it
    } 
    finally {
        if (conn != null) {
            try {
                conn.close();
            }
            catch (SQLException e) {
                // handle error disconnecting from the database.
            }
        }
    }

除了关闭连接外,完成Statements 和PreparedStatements 后关闭它们也是一个好习惯。

第四,每次执行循环时,您都在创建一个新的数据库连接(这将在服务器上创建一个新进程)。这是完全没有必要的。您应该在循环之前创建一次数据库连接,在整个循环中使用相同的连接,并且只在循环结束时关闭连接。因为您在一个循环中创建了如此多的连接,并且没有关闭其中任何一个,所以您最终会很快达到数据库进程的限制。

第五,我强烈建议使用 Oracle JDBC 驱动程序(类名oracle.jdbc.OracleDriver,在 JAR 中命名ojdbc6.jar或类似),而不是“旧”的 JDBC-ODBC 桥驱动程序,它将在 Java 8 中从 Java 中删除

第六,即使按照我的建议修复了您的 SQL,也不太可能按照您的意愿行事。目前只会为当月最后一天对应的列设置一个值。您是否可能打算用名称更新列y

编辑以回应您编辑的问题:问题出在这一行:

            pstmt.setString(z, s[y]);                   //getting error in this line as per the debug report.

这应该是

            pstmt.setString(1, s[y]);

该数字1是查询中占位符的索引?。这些索引从 1 开始。您的查询中只有一个占位符,因此它的索引为 1。

于 2013-04-24T20:12:00.257 回答