简体   繁体   English

Java SQL 异常 - r.getString 没有从 resultSet 中获取列

[英]Java SQL Exception - r.getString doesn't get column from resultSet

I keep getting SQLException on String passwordr = r.getString(3);我不断收到 SQLException on String passwordr = r.getString(3); . . From my understanding is that r.getString gets column 3 from the result set, which contains the password in table.根据我的理解,r.getString 从结果集中获取第 3 列,其中包含表中的密码。 Later on I will compare passwordr to whatever is in txtPassword.稍后我会将 passwordr 与 txtPassword 中的任何内容进行比较。 Why does it keep going to SQL Exception?为什么它会继续出现 SQL 异常?

If I hover over "passwordr" it says "Not a known variable in the current context" within NetBeans - I'm not sure if this matters.如果我将鼠标悬停在“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");
            }
        }    
        
            
    }

This block of code has multiple issues, some minor and some significant.这段代码有多个问题,有些是次要的,有些是重要的。 The version I am providing here still has some issues, but addresses many of the problems of the original code.我在这里提供的版本仍然存在一些问题,但解决了原始代码的许多问题。

Orthogonal to the problem of getting this code to work is the larger question of whether it is appropriate to store passwords in plaintext in a database.与让这段代码正常工作的问题正交的是一个更大的问题,即在数据库中以明文形式存储密码是否合适。 I won't address that here, as this is still an appropriate bit of code for learning Java and JDBC.我不会在这里解决这个问题,因为这仍然是学习 Java 和 JDBC 的合适代码。

See the commented note pointers in the code.请参阅代码中的注释注释指针。

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");
  }
}
  1. The original SQL was being created with user-provided text in a quoted string.最初的 SQL 是用用户提供的带引号的字符串创建的。 This kind of construct is just begging for a SQL Injection attack.这种构造只是在乞求 SQL 注入攻击。 It is almost always best to use bind variables instead.最好使用绑定变量来代替。 In the very rare case where that cannot be done, the user-provided data must be sanitized.在极少数情况下无法做到这一点,必须清理用户提供的数据。 Do some research on SQL Injection Attack to see how easy it is for someone to get your code to execute unwanted SQL.对 SQL 注入攻击进行一些研究,看看有人让您的代码执行不需要的 SQL 是多么容易。 Besides the benefit for security, bind variables improve the database's ability to share the parsed SQL.除了安全方面的好处之外,绑定变量还提高了数据库共享已解析 SQL 的能力。 In order to use bind variables, you will need to use PreparedStatement instead of Statement .为了使用绑定变量,您需要使用PreparedStatement而不是Statement Finally, the trailing semicolon in the SQL is not needed (at least in Oracle, not sure about others) and might cause syntax issues.最后,不需要 SQL 中的尾随分号(至少在 Oracle 中,其他不确定)并且可能会导致语法问题。
  2. This is where the binding happens.这是绑定发生的地方。 The statement has been created, but now we have to bind the user-provided value.语句已创建,但现在我们必须绑定用户提供的值。
  3. You won't have any results until you first call r.next() .在您第一次调用r.next()之前,您不会有任何结果。
  4. It is far safer to get the data from the result set by column name vs. position.按列名与位置从结果集中获取数据要安全得多。 This is particularly important when working with large numbers of columns, as database tables might have different column order in Dev/Test/Stage/Prod based on how they were modified over time.这在处理大量列时尤为重要,因为数据库表在 Dev/Test/Stage/Prod 中可能具有不同的列顺序,这取决于它们随时间的修改方式。
  5. To be pedantic, the result set should also be closed.为了学究,结果集也应该关闭。 In order to simplify all of these verbose try/catch sections, consider using "Try with resources".为了简化所有这些冗长的 try/catch 部分,请考虑使用“尝试资源”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM