java - MySQL ResultSet 可滚动/可更新未按预期工作

标签 java mysql jdbc scroll resultset

我有一个测试 JDBC 程序,它试图改变结果集的可滚动性和可更新性特性。不幸的是,TYPE_CONCUR_ 的所有组合似乎都会产生相同的结果(TYPE_SCROLL_INSENSITIVECONCUR_READ_ONLY)。

即使使用默认设置 (TYPE_FORWARD_ONLY),也可以滚动 ResultSet。谁能解释这是为什么?

我正在使用 MySQL 5.6 和 JDK7。这是代码:

public class ResultSetTest3 {

    public static void main(String[] args)
    {
        Connection conn;

        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost/bd", "user", "password");

            Statement sta = conn.createStatement();
            sta.execute("DELETE FROM test");
            sta.close();

            PreparedStatement ps = conn.prepareStatement("INSERT INTO test VALUES(?, ?)");
            for(int i=1; i<=100; i++)
            {
                ps.setInt(1, i);
                ps.setString(2, "Teste " + i);
                ps.addBatch();
            }
            ps.executeBatch();
            ps.close();

            System.out.println("TYPE_FORWARD_ONLY  CONCUR_READ_ONLY");
            result(conn, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
            System.out.println("===================================");

            System.out.println("TYPE_SCROLL_INSENSITIVE  CONCUR_READ_ONLY");
            result(conn, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
            System.out.println("===================================");

            System.out.println("TYPE_SCROLL_SENSITIVE  CONCUR_READ_ONLY");
            result(conn, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
            System.out.println("===================================");

            System.out.println("TYPE_FORWARD_ONLY  CONCUR_UPDATABLE");
            result(conn, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
            System.out.println("===================================");

            System.out.println("TYPE_SCROLL_INSENSITIVE  CONCUR_UPDATABLE");
            result(conn, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
            System.out.println("===================================");

            System.out.println("TYPE_SCROLL_SENSITIVE  CONCUR_UPDATABLE");
            result(conn, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            System.out.println("===================================");

            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static void result(Connection conn, int type, int update) throws SQLException
    {
        Statement sta = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
        ResultSet rs = sta.executeQuery("SELECT * FROM test");

        System.out.println(rs.getConcurrency() + " " + update);
        System.out.println(rs.getType() + " " + type);

        try
        {
            rs.absolute(10);
            System.out.println(rs.getInt(1) + " - " + rs.getString(2));

            rs.relative(20);
            System.out.println(rs.getInt(1) + " - " + rs.getString(2));

            rs.previous();
            System.out.println(rs.getInt(1) + " - " + rs.getString(2));

            rs.first();
            System.out.println(rs.getInt(1) + " - " + rs.getString(2));

            try {
                System.out.println("AGORA!!!");
                Thread.sleep(20000);
            } catch (Exception e) {
                System.out.println(e);
            }
            rs.absolute(3);
            System.out.println(rs.getInt(1) + " - " + rs.getString(2));
        }
        catch(SQLException e)
        {
            System.out.println("Not Scrollable");
        }

        try
        {
            rs.next();
            rs.next();
            rs.next();
            rs.next();

            rs.deleteRow();

            rs.next();
            rs.updateString(2, "TesteUpdate");

            rs.insertRow();
        }
        catch(SQLException e)
        {
            System.out.println("Not Updatable");
        }

        rs.close();
        sta.close();
    }
}

最佳答案

正如 Mark Rotteveel 在对该问题的评论中提到的,MySQL 默认缓存 ResultSet 数据(也在博客文章中讨论过 本·克里斯滕森 here ).这种缓存的明显副作用是 MySQL Connector/J 会将 TYPE_FORWARD_ONLY 结果集“升级”为实际可滚动:

Statement s = dbConnection.createStatement(
        ResultSet.TYPE_FORWARD_ONLY, 
        ResultSet.CONCUR_READ_ONLY);
ResultSet rs = s.executeQuery("SELECT * FROM testdata");
rs.last();
System.out.println(String.format("Current row number: %d", rs.getRow()));
rs.previous();
System.out.println(String.format("Current row number: %d", rs.getRow()));

显示

Current row number: 3
Current row number: 2

根据上面引用的博客文章,防止缓存和“流式传输”ResultSet 数据的方法是使用 Statement.setFetchSize:

Statement s = dbConnection.createStatement(
        ResultSet.TYPE_FORWARD_ONLY, 
        ResultSet.CONCUR_READ_ONLY);
s.setFetchSize(Integer.MIN_VALUE);
ResultSet rs = s.executeQuery("SELECT * FROM testdata");
rs.next();
System.out.println("Data from first row: " + rs.getString(2));
System.out.println("now let's try rs.last() ...");
try {
    rs.last();
    System.out.println("... Okay, done.");
} catch (Exception e) {
    System.out.println("... Exception: " + e.getMessage());
}

导致

Data from first row: Gord
now let's try rs.last() ...
... Exception: Operation not supported for streaming result sets

关于java - MySQL ResultSet 可滚动/可更新未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23817619/

相关文章:

mysql - SQL 重复数据删除有帮助吗?

php - MySQL插入列值与自动增量相同的行

java - 当我尝试使用 JDBC 连接到 MySQL 时遇到 "Communications link failure"错误

java - 使用不同的 log4j 配置重新运行失败的测试(设置为调试)?

java - 如何清理 ThreadLocals

javascript - 保存对象列表返回 Cannot deserialize 错误

java - 为什么可以创建基元数组的集合而不是基元集合

mysql - 我可以使用 Group By 计算多列吗?

java - 数据源到底是什么?这有什么区别呢?

java - 如何使用 request-handler-advice-chain 和 ExpressionEvaluatingRequestHandlerAdvice?