Java SQL 异常 - r.getString 没有从结果集中获取列
Posted
技术标签:
【中文标题】Java SQL 异常 - r.getString 没有从结果集中获取列【英文标题】:Java SQL Exception - r.getString doesn't get column from resultSet 【发布时间】:2021-11-15 08:06:41 【问题描述】:我在 String passwordr = r.getString(3); 上不断收到 SQLException。据我了解,r.getString 从结果集中获取第 3 列,其中包含表中的密码。稍后我会将密码器与 txtPassword 中的任何内容进行比较。为什么老是出现 SQL Exception?
如果我将鼠标悬停在“passwordr”上,它会在 NetBeans 中显示“当前上下文中不是已知变量” - 我不确定这是否重要。
try
// load the sql driver
Class.forName(ConnectionDetails.getDriver());
// attempt to connect
con = DriverManager.getConnection(url, username, password);
System.out.println("Connected to the database: "+ ConnectionDetails.getDb());
// prepare an sql statement
stmt = con.createStatement();
String sql = "SELECT * FROM tblusers WHERE fldusername='" + txtUsername.getText() + "';";
// run the query
System.out.println("Before query");
System.out.println(sql);
r = stmt.executeQuery(sql);
System.out.println("After query");
String passwordr = r.getString(1); //FAILS AT THIS LINE
System.out.println(passwordr);
if ( r.next() )// if this returns false there are no records
// username found
lblResult.setText("USERNAME Found");
if (passwordr.equals(new String((txtPassword.getPassword()))))
lblResult.setText("PASSWORD Correct");
else
lblResult.setText("PASSWORD Incorrect");
else
lblResult.setText("USERNAME NOT FOUND");
catch(ClassNotFoundException cnfe)
System.err.println("Error finding connection details class");
catch(SQLException sqlE)
System.err.println("SQL Error");
finally
// close the statement object
try
if( stmt != null )
stmt.close();
System.out.println("Statement object closed");
catch(SQLException se)
System.err.println("Error: Statement not closed");
// close connection to the database
try
if( con != null )
con.close();
System.out.println("Connection to db closed");
catch(SQLException se)
System.err.println("Error: Connection to db not closed");
【问题讨论】:
问题太多,但最大的问题可能是您将明文密码直接存储在用户表中。 不要那样做。散列密码并存储加密版本。然后,为了比较,散列密码输入并将其与表中的内容进行比较。 执行 SELECT * 然后对列的顺序进行假设可能不是一个好主意。最好使用getString(columnName)
而不是getString(3)
。
您必须先对结果集调用next()
,然后才能检索列。结果最初位于第一行之前。另外,在提问时,请发布minimal reproducible example 并包含异常堆栈跟踪。
【参考方案1】:
这段代码有多个问题,有些小,有些很重要。我这里提供的版本还有一些问题,但是解决了原代码的很多问题。
与使该代码工作的问题正交的是,是否适合以明文形式将密码存储在数据库中。我不会在这里讨论这个问题,因为这仍然是学习 Java 和 JDBC 的合适代码。
查看代码中注释的注释指针。
try
// load the sql driver
Class.forName(ConnectionDetails.getDriver());
// attempt to connect
con = DriverManager.getConnection(url, username, password);
System.out.println("Connected to the database: "+ ConnectionDetails.getDb());
// prepare an sql statement
String sql = "SELECT * FROM tblusers WHERE fldusername=?"; // <----- Note 1
// Now we need to use a prepared statement, so we can use a bind variable
stmt = con.prepareStatement(sql);
// Bind the user data
stmt.setString(1, txtUsername.getText()); // <----- Note 2
// run the query
System.out.println("Before query");
System.out.println(sql);
r = stmt.executeQuery();
System.out.println("After query");
if ( r.next() )// if this returns false there are no records // <----- Note 3
String passwordr = r.getString("PASSWORD_FIELD_NAME"); // <----- Note 4
System.out.println(passwordr);
// username found
lblResult.setText("USERNAME Found");
if (passwordr.equals(new String((txtPassword.getPassword()))))
lblResult.setText("PASSWORD Correct");
else
lblResult.setText("PASSWORD Incorrect");
else
lblResult.setText("USERNAME NOT FOUND");
catch(ClassNotFoundException cnfe)
System.err.println("Error finding connection details class");
catch(SQLException sqlE)
System.err.println("SQL Error");
finally
// close the Result Set object // <----- Note 5
try
if( r != null )
r.close();
System.out.println("Result set object closed");
catch(SQLException se)
System.err.println("Error: Result set not closed");
// close the statement object
try
if( stmt != null )
stmt.close();
System.out.println("Statement object closed");
catch(SQLException se)
System.err.println("Error: Statement not closed");
// close connection to the database
try
if( con != null )
con.close();
System.out.println("Connection to db closed");
catch(SQLException se)
System.err.println("Error: Connection to db not closed");
-
原始 SQL 是使用用户提供的文本在带引号的字符串中创建的。这种构造只是在乞求 SQL 注入攻击。几乎总是最好使用绑定变量。在极少数情况下无法做到这一点,用户提供的数据必须进行清理。对 SQL 注入攻击做一些研究,看看有人让你的代码执行不需要的 SQL 是多么容易。除了安全性的好处之外,绑定变量还提高了数据库共享已解析 SQL 的能力。为了使用绑定变量,您需要使用
PreparedStatement
而不是Statement
。最后,SQL 中的结尾分号是不需要的(至少在 Oracle 中,其他的不确定),这可能会导致语法问题。
这是绑定发生的地方。语句已创建,但现在我们必须绑定用户提供的值。
在您第一次致电 r.next()
之前,您不会有任何结果。
从结果集中按列名与位置获取数据要安全得多。这在处理大量列时尤其重要,因为数据库表在 Dev/Test/Stage/Prod 中可能具有不同的列顺序,具体取决于它们随时间的修改方式。
为了迂腐,结果集也应该关闭。为了简化所有这些冗长的 try/catch 部分,请考虑使用“Try with resources”。
【讨论】:
以上是关于Java SQL 异常 - r.getString 没有从结果集中获取列的主要内容,如果未能解决你的问题,请参考以下文章
Java 异常 java.sql.SQLException: HikariDataSource HikariDataSource (HikariPool-1) 已关闭
Bug解决 java.sql.SQLSyntaxErrorException 异常