SQL Insert in Java class 在 SQL 语句中抛出错误
SQL Insert in Java class throws error on the SQL Statement
当 运行 我的 servlet 的 postmethod 时,我的语句总是出错。但是,当我只是尝试直接在数据库中执行它时,它工作得很好。
我正在使用 tomcat 9 服务器;和 postgres 数据库。 Java 开放逻辑 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>");
}
您的查询似乎没有问题,因此您尝试插入的数据库肯定有问题。
你能指定你试图插入的模式吗?例如:
"INSERT INTO test.testinserts (lastname, firstname, city) VALUES ("+ lastname + "," + firstname + "," + location + ");"
此外,请检查您的数据库连接。例如,尝试手动插入一些数据,然后从您的代码中查询它。
编辑:如其他帖子所述,这是为了检查公开的示例。
您应该构建执行 VALUES (?, ?, ?) 的查询,然后使用 stm.setString(1, lastname)、stm.setString(2, firstname) 等来 避免 SQL 注入.
另一个(已接受的)答案 是一个安全漏洞,将使您的数据库 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-ese for 'comment',所以它后面的所有内容都被完全忽略了。换句话说,插入 1 行,然后删除整个 table,然后格式化您的硬盘。
这是逃不掉的。相反,解决方法是 永远不会 将用户输入直接注入您的数据库。换句话说,所有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的点是.setString命令设置了整个字符串,它不只是把我输入的第一个问号换掉.安全漏洞现已完全修复。
资源
第二个问题是资源。您的数据库引擎只允许您在开始拒绝连接之前打开少数连接。因此你必须关闭它。如果你不关闭它,在 20 左右插入你的 java 应用程序(或者,就此而言,任何其他应用程序)将无法再连接到数据库,因为数据库认为它是 'too busy',因为仍然有 20 个打开的连接。这些连接早已被废弃,但 java 不会当场进行垃圾收集 - 这些对象只是在撒谎,什么都不做,但数据库引擎不知道。
您可以调用 close()
,但是如果您的代码抛出异常,或者您编写 return;你忘了你现在忘记关闭了?
解决方案是尝试使用资源。请注意,Connection、和 PreparedStatement、和 ResultSet 都是需要这种处理的资源:
try (Connection con = ....;
PreparedStatement ps = ....;) {
ps.setString(1, ...);
ps.setString(2, ...);
ps.setString(3 ...);
ps.execute();
}
try(){}
构造告诉 java:运行 创建内容(对象的创建 con
和 ps
指的),以及然后 运行 {}
中的东西,但无论代码 退出 那些 {}
,还是 'naturally' (运行 结束),无论是通过控制流(中断、继续或从中退出 return;
),还是通过异常(抛出一些东西),首先在这些资源上调用 close()
,并且仅然后继续。
当 运行 我的 servlet 的 postmethod 时,我的语句总是出错。但是,当我只是尝试直接在数据库中执行它时,它工作得很好。
我正在使用 tomcat 9 服务器;和 postgres 数据库。 Java 开放逻辑 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>");
}
您的查询似乎没有问题,因此您尝试插入的数据库肯定有问题。 你能指定你试图插入的模式吗?例如: "INSERT INTO test.testinserts (lastname, firstname, city) VALUES ("+ lastname + "," + firstname + "," + location + ");"
此外,请检查您的数据库连接。例如,尝试手动插入一些数据,然后从您的代码中查询它。
编辑:如其他帖子所述,这是为了检查公开的示例。 您应该构建执行 VALUES (?, ?, ?) 的查询,然后使用 stm.setString(1, lastname)、stm.setString(2, firstname) 等来 避免 SQL 注入.
另一个(已接受的)答案 是一个安全漏洞,将使您的数据库 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-ese for 'comment',所以它后面的所有内容都被完全忽略了。换句话说,插入 1 行,然后删除整个 table,然后格式化您的硬盘。
这是逃不掉的。相反,解决方法是 永远不会 将用户输入直接注入您的数据库。换句话说,所有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的点是.setString命令设置了整个字符串,它不只是把我输入的第一个问号换掉.安全漏洞现已完全修复。
资源
第二个问题是资源。您的数据库引擎只允许您在开始拒绝连接之前打开少数连接。因此你必须关闭它。如果你不关闭它,在 20 左右插入你的 java 应用程序(或者,就此而言,任何其他应用程序)将无法再连接到数据库,因为数据库认为它是 'too busy',因为仍然有 20 个打开的连接。这些连接早已被废弃,但 java 不会当场进行垃圾收集 - 这些对象只是在撒谎,什么都不做,但数据库引擎不知道。
您可以调用 close()
,但是如果您的代码抛出异常,或者您编写 return;你忘了你现在忘记关闭了?
解决方案是尝试使用资源。请注意,Connection、和 PreparedStatement、和 ResultSet 都是需要这种处理的资源:
try (Connection con = ....;
PreparedStatement ps = ....;) {
ps.setString(1, ...);
ps.setString(2, ...);
ps.setString(3 ...);
ps.execute();
}
try(){}
构造告诉 java:运行 创建内容(对象的创建 con
和 ps
指的),以及然后 运行 {}
中的东西,但无论代码 退出 那些 {}
,还是 'naturally' (运行 结束),无论是通过控制流(中断、继续或从中退出 return;
),还是通过异常(抛出一些东西),首先在这些资源上调用 close()
,并且仅然后继续。