9

SQLite の JDBC ドライバーに問題があります。

SELECT ステートメントでクエリを実行しています。

ResultSet(0 行) を取得すると、呼び出し時に「Closed ResultSet」例外がスローされgetString(1)ます。

以前のJDBCの経験があまりないので、私の理論(JavaDocsで確認できませんでしたResultSet)は

  • getString(1)空 (ゼロ行) の結果セットでは機能しません (設計上またはバグのため)。
  • ResultSetの「open」フラグはfalseゼロ行に設定されています(これも設計またはバグによるものです)

このバグ レポートを見ましたが、関連しているかどうかはわかりません。

私の質問は次のとおりです。

  1. 上記の理論は正しいですか?
  2. バグですか?特徴?(もしそうなら、誰かがドキュメントを指摘できますか?)
  3. SQLIte の JDBC に固有のものResultSetですか、それともすべての JDBC ドライバーのジェネリックですか?
  4. そのようなことをする正しい方法は何ですか??

#4の場合、私の解決策は、isFirst()呼び出し直後に使用executeQuery()して、結果セットに行があるかどうかを確認することでした。これはベストプラクティスのアプローチですか?

(結果セットは本当に必要なく、ゼロ以外のフラグだけだったので、単純にカウントを選択することもできましたが、選択の結果を気にした場合の正しいことを知りたいです)

ありがとう!

4

4 に答える 4

18

空かどうかはわかりませんが、次のことを行うと常に問題が発生します。

resultSet = statement.executeQuery(sql);
string = resultSet.getString(1); // Epic fail. The cursor isn't set yet.

これはバグではありません。これは文書化された動作です。すべてのまともなJDBCチュートリアルはそれについて言及しています。next()データにアクセスする前に、を使用してResultSetのカーソルを設定する必要があります。

おそらく一意の行が存在するかどうかに実際に興味がある場合は、の結果を確認してくださいnext()。たとえば、架空UserDAOのクラスでは:

public boolean exist(String username, String password) throws SQLException {
    boolean exist = false;

    try (
        Connection connection = database.getConnection();
        PreparedStatement statement = connection.prepareStatement("SELECT id FROM user WHERE username = ? AND password = MD5(?)");
    ) {
        statement.setString(1, username);
        statement.setString(2, password);

        try (ResultSet resultSet = statement.executeQuery()) {
            exist = resultSet.next();
        }
    }

    return exist;
}

実際に0行または1行しか期待できない場合は、次のようにします。

public User find(String username, String password) throws SQLException {
    User user = null;

    try (
        Connection connection = database.getConnection();
        PreparedStatement statement = connection.prepareStatement("SELECT id, username, email, birthdate FROM user WHERE username = ? AND password = MD5(?)");
    ) {
        statement.setString(1, username);
        statement.setString(2, password);

        try (resultSet = statement.executeQuery()) {
            if (resultSet.next()) {
                user = new User(
                    resultSet.getLong("id"),
                    resultSet.getString("username"),
                    resultSet.getString("email"),
                    resultSet.getDate("birthdate")); 
            }
        }
    }

    return user;
}

次に、ビジネス/ドメインオブジェクトでそれに応じて処理します。

User user = userDAO.find(username, password);

if (user != null) {
    // Login?
}
else {
    // Show error?
}

実際に0行または多数の行しか期待できない場合は、次のようにします。

public List<User> list() throws SQLException {
    List<User> users = new ArrayList<User>();

    try (
        Connection connection = database.getConnection();
        PreparedStatement statement = connection.prepareStatement("SELECT id, username, email, birthdate FROM user");
        ResultSet resultSet = statement.executeQuery();
    ) {
        while (resultSet.next()) {
            users.add(new User(
                resultSet.getLong("id"),
                resultSet.getString("username"),
                resultSet.getString("email"),
                resultSet.getDate("birthdate")));
        }
    }

    return users;
}

次に、ビジネス/ドメインオブジェクトでそれに応じて処理します。

List<User> users = userDAO.list();

if (!users.isEmpty()) {
    int count = users.size();
    // ...
}
else {
    // Help, no users?
}
于 2009-11-29T02:26:05.387 に答える
6
while (rs.next()) {
 // process the row
}
于 2009-11-28T21:49:10.883 に答える
5

ResultSetの JavaDocs から:

ResultSet オブジェクトは、現在のデータ行を指すカーソルを維持します。最初、カーソルは最初の行の前に配置されます。next メソッドはカーソルを次の行に移動し、ResultSet オブジェクトに行がなくなると false を返すため、while ループで使用して結果セットを反復処理できます。

データを読み取ろうとする前にResultSet、たとえば を呼び出して、 を行に配置する必要があります。next()への呼び出しがnext()返されたfalse場合、結果セットは空です。

于 2009-11-28T22:10:13.617 に答える
1

そのような種類の問題については、そのように使用できます

while(rs.next())
{
    String name=rs.getString("Name");
    int roll_no=Integer.parseInt(rs.getString("Roll"));
}
finally
{
    try
    {
        rs.close();
        pst.close();
    }
    catch(Exception ee)
    {
    }
}

Joptionpane.showmessahedialog(this,ee);
于 2015-05-07T12:37:26.913 に答える