Connection、Statement、PreparedStatement、Resultset注意点メモ

5656 ワード

まずいくつかのテスト結果を記録します.
テスト環境
MySQL:mysql-connector-java-5.1.29.jar
Java:1.7.0_67
テストA
コード:
        PreparedStatement pstmt = conn
                .prepareStatement("select id from world.city limit 3");
        ResultSet rs = pstmt.executeQuery();
        while (rs.next()) {
            System.out.println(rs.getString(1));
        }
        System.out.println();

        PreparedStatement pstmt2 = conn
                .prepareStatement("select countrycode from world.city limit 3");
        ResultSet rs2 = pstmt2.executeQuery();
        while (rs2.next()) {
            System.out.println(rs2.getString(1));
        }

        System.out.println(pstmt.isClosed());
        System.out.println(rs.isClosed());
        System.out.println(pstmt2.isClosed());
        System.out.println(rs2.isClosed());
        System.out.println(conn.isClosed());
        System.out.println();

        conn.close();
        System.out.println(pstmt.isClosed());
        System.out.println(rs.isClosed());
        System.out.println(pstmt2.isClosed());
        System.out.println(rs2.isClosed());
        System.out.println(conn.isClosed());
        System.out.println();

結果:
false
false
false
false
false

true
true
true
true
true

結論:
接続が閉じると、関連するResultSetとPreparedStatementが閉じます.
テストB
コード:
        PreparedStatement pstmt = null;
        ResultSet rs1 = null;
        ResultSet rs2 = null;
        
        Statement st = null;
        ResultSet rs3 = null;
        ResultSet rs4 = null;
        
        try {
            pstmt = conn.prepareStatement(
                    "select name from world.city where name like ? limit 3");
            pstmt.setString(1, "a%");
            rs1 = pstmt.executeQuery();
            rs2 = null;
            while (rs1.next()) {
                System.out.println(rs1.getString(1));

                pstmt.setString(1, "b%");
                rs2 = pstmt.executeQuery();
                while (rs2.next()) {
                    System.out.println(rs2.getString(1));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        try {
            st = conn.createStatement();
            rs3 = st.executeQuery(
                    "select name from world.city where name like 'a%' limit 3");
            rs4 = null;
            while (rs3.next()) {
                System.out.println(rs3.getString(1));

                rs4 = st.executeQuery(
                        "select name from world.city where name like 'b%' limit 3");
                while (rs4.next()) {
                    System.out.println(rs4.getString(1));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(pstmt.isClosed());
        System.out.println(rs1.isClosed());
        System.out.println(rs2.isClosed());
        System.out.println(st.isClosed());
        System.out.println(rs3.isClosed());
        System.out.println(rs4.isClosed());
        System.out.println(conn.isClosed());
        System.out.println();

結果:
java.sql.SQLException: Operation not allowed after ResultSet closed

java.sql.SQLException: Operation not allowed after ResultSet closed
    
false
true
false
false
true
false
false

結論:
同じStatementオブジェクトまたはPreparedStatementオブジェクトには、アクティブなResultSetのみが関連付けられます.
テストC
コード:
        PreparedStatement pstmt = conn
                .prepareStatement("select id from world.city limit 3");
        ResultSet rs = pstmt.executeQuery();
        while (rs.next()) {
            System.out.println(rs.getString(1));
        }
        System.out.println();
        
        PreparedStatement pstmt_old = pstmt;
        pstmt = conn.prepareStatement("select name from world.city where name like ? limit 3");
        pstmt.setString(1, "a%");
        ResultSet rs2 = pstmt.executeQuery();
        while (rs2.next()) {
            System.out.println(rs2.getString(1));
        }

        System.out.println(pstmt.isClosed());
        System.out.println(rs.isClosed());
        System.out.println(pstmt_old.isClosed());
        System.out.println(rs2.isClosed());
        System.out.println(conn.isClosed());
        System.out.println();
        
        pstmt.close();
        System.out.println(pstmt.isClosed());
        System.out.println(rs.isClosed());
        System.out.println(pstmt_old.isClosed());
        System.out.println(rs2.isClosed());
        System.out.println(conn.isClosed());
        System.out.println();

        conn.close();
        System.out.println(pstmt.isClosed());
        System.out.println(rs.isClosed());
        System.out.println(pstmt_old.isClosed());
        System.out.println(rs2.isClosed());
        System.out.println(conn.isClosed());
        System.out.println();

結果:
false
false
false
false
false

true
false
false
true
false

true
true
true
true
true

結論:
PreparedStatementオブジェクトが閉じずに他のPreparedStatementが関連付けられている場合、古いPreparedStatementとResultSetはConnectionが閉じるまで閉じません.接続プールを使用している場合、メモリが漏洩する可能性があります.
より良い方法:
  • は、Statementの代わりにPreparedStatementを使用する一方で、複数回の実行文の効率を向上させる一方で、SQLの接合による注入攻撃を防止する
  • である.
  • PreparedStatementを閉じることに注意してください.接続プールを使用する場合は特に注意してください.Java 7以上はtry-with-resource文を使用することをお勧めします.簡潔です.Java 7以下ではクローズ時にもtry-catchを注意し、ResultSet、PreparedStatement、Connectionの順にできるだけクローズします.
  • ResultSetを渡さずにRowSetを使用します.