【问题标题】:java access try code block from a separate classjava从一个单独的类访问try代码块
【发布时间】:2017-09-29 06:38:50
【问题描述】:

您好,我正在尝试在 java 中使用 Access 数据库,但遇到了一些麻烦。下面我已经建立了到我的数据库的连接。

public class DBAccess {
DBAccess() {
    try {
        Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
        String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=CFPDB.mdb;";
        Connection conn = DriverManager.getConnection(database, "", "");
        Statement s = conn.createStatement();
    }
    catch(Exception ex) {
        ex.printStackTrace();
    }
}
}

我需要使用我的 gui 类访问 's' 变量表单以检查密码:

else if(event.getSource() == loginSubmitButton){
        DBAccess loginCheck;
        String selFromTable = "SELECT PASSWORD FROM USERS WHERE USERNAME = '" + loginUsername.getText() + "'; ";
        loginCheck.s.execute(selFromTable);
        ResultSet retrievedPassword = loginCheck.s.getResultSet();
        String password = retrievedPassword.getString(1);
        String password_entered = loginPassword.getText();
    }

但我的编译器说它找不到符号 - 变量“s”。 DBAccess 类在我的 gui 的单独文件中,但都在同一个包中。任何帮助都会很棒。 :)

【问题讨论】:

  • 为了让类与世界分享事物,我们有类字段和吸气剂。
  • s 不是一个字段,它是一个变量,一旦创建对象就会超出范围。另一个问题是该对象永远不会被创建,并且您永远不会清理您的 SQL,从而使您容易受到 SQL 注入的攻击。

标签: java sql ms-access


【解决方案1】:

Java 不是这样工作的,每个变量都有自己的作用域,表明它在哪里定义,在哪里容易被使用以及何时被垃圾收集器收集。一般来说,在开始时记住它的一个好方法是变量只会在最近的括号 {} 内“存活”。

在这种情况下,您的 's' 变量对于 try-catch 块的范围是有限的,因此一旦该块结束,s 变量就无法再访问,您可以通过尝试编译此代码来验证这一点:

DBAccess() {
    try {
        Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
        String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=CFPDB.mdb;";
        Connection conn = DriverManager.getConnection(database, "", "");
        Statement s = conn.createStatement();
        s.execute(""); // compiles without problem.
    }
    catch(Exception ex) {
        s.execute(""); // does not compile.
        ex.printStackTrace();
    }
    s.execute(""); // does not compile.
}

所以你最好的选择是将 s 声明为一个类字段:

public class DBAccess {

    private Statement s;

    DBAccess() {
        try {
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=CFPDB.mdb;";
            Connection conn = DriverManager.getConnection(database, "", "");
            s = conn.createStatement();
        }
        catch(Exception ex) {
            ex.printStackTrace();
        }
    }

    public Statement getStatement() {
        return s;
    }
}

然后通过它的 getter 方法访问它。顺便说一句,请记住通过其构造函数(第 2 行)实例化您的对象

else if(event.getSource() == loginSubmitButton){
        DBAccess loginCheck = new DBAccess(); // invoke constructor
        String selFromTable = "SELECT PASSWORD FROM USERS WHERE USERNAME = '" + loginUsername.getText() + "'; ";
        loginCheck.getStatement().execute(selFromTable);
        ResultSet retrievedPassword = loginCheck.getStatement().getResultSet();
        String password = retrievedPassword.getString(1);
        String password_entered = loginPassword.getText();
}

另一个我并不真正推荐的选项(但在这里只是为了让您知道)是将 s 字段声明为公共:

public class DBAccess {

    public Statement s;

    DBAccess() {
        try {
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=CFPDB.mdb;";
            Connection conn = DriverManager.getConnection(database, "", "");
            s = conn.createStatement();
        }
        catch(Exception ex) {
            ex.printStackTrace();
        }
    }

然后你可以按照你想要的方式访问它:

loginCheck.s.execute(selFromTable);

【讨论】:

  • 虽然 Matěj Račinský 的回答也是正确的,但 SEAang 的回答更简洁,并且写得很好,并附有解释,以帮助未来的观众了解这个问题。顺便说一句,谢谢你们两个:)
【解决方案2】:

你需要从 s 中创建字段,因为只要拥有它的对象存在,字段就存在。当 DBAccess 构造函数完成时, s 现在消失了。所以你想要这样的东西:

public class DBAccess {

private Statement s;

DBAccess() {
    try {
        Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
        String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=CFPDB.mdb;";
        Connection conn = DriverManager.getConnection(database, "", "");
        s = conn.createStatement();
    }
    catch(Exception ex) {
        ex.printStackTrace();
    }
}

public Statement getStatement() {
    return s;
}
}

并在您的 gui 类中使用 getter 访问 s:

else if(event.getSource() == loginSubmitButton){
    DBAccess loginCheck;
    String selFromTable = "SELECT PASSWORD FROM USERS WHERE USERNAME = '" + loginUsername.getText() + "'; ";  //this is vulnerable to SQL injection, use prepared statements, see for example, here https://www.mkyong.com/jdbc/jdbc-preparestatement-example-select-list-of-the-records/
    loginCheck.getStatement().execute(selFromTable);
    ResultSet retrievedPassword = loginCheck.s.getResultSet();
    String password = retrievedPassword.getString(1);
    String password_entered = loginPassword.getText();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-09
    • 2017-10-21
    • 2016-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多