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 没有从结果集中获取列的主要内容,如果未能解决你的问题,请参考以下文章

SQL异常列无效,java sql语句

Java 异常 java.sql.SQLException: HikariDataSource HikariDataSource (HikariPool-1) 已关闭

Bug解决 java.sql.SQLSyntaxErrorException 异常

java SQL异常分析

java.sql.SQLException:Io 异常:套接字读取超时与关闭连接

更新语句Java sql异常:期望的参数太少