0

我将 JDBC 与 mysql-connector-java-6.0.2.jar 一起使用,除非我做错了什么,否则我认为 DatabaseMetaData.ownDeletesAreVisible 和 DatabaseMetaData.deletesAreDetected 实现在彼此之间以某种方式不一致。

以下是 JDBC 规范关于 ownDeletesAreVisible 的说明:

" ...如果删除的行被删除或替换为空行,则DatabaseMetaData.ownDeletesAreVisible(int type)方法将返回true。如果ResultSet对象仍然包含已删除的行,则返回false,这意味着删除不作为对给定类型的 ResultSet 对象的更改可见... "

关于 deletesAreDetected:

...如果从 ResultSet 对象中删除的行被删除,则方法 deletesAreDetected 返回 false,如果删除的行被空行或无效行替换,则返回 true...

我将输出添加为注释:

import static java.sql.ResultSet.CONCUR_UPDATABLE;
import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
import java.sql.*;

public class Deletions {

    public static void main(String[] args) throws SQLException {

        try (Connection conn = DBUtils.getConnection();
                Statement stmt = conn.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_UPDATABLE);
                ResultSet rs = stmt.executeQuery("select * from book")) {

            DatabaseMetaData dbmd = conn.getMetaData();

            //prints false
            System.out.println(dbmd.ownDeletesAreVisible(TYPE_SCROLL_INSENSITIVE));

            // prints false. Controversy?
            System.out.println(dbmd.deletesAreDetected(TYPE_SCROLL_INSENSITIVE)); 

            // Prints everything including foo
            printAll(rs); 


            // deletes foo
            while (rs.next()) {
                String title = rs.getString(2);
                if (title.equalsIgnoreCase("foo")) {
                    rs.deleteRow();
                }
            }

            // Prints everything without foo
            printAll(rs);

        }
    }

        private static void printAll(ResultSet rs) throws SQLException {
            rs.beforeFirst();
            while (rs.next()) {
                System.out.println(rs.getString(2));
            }
            rs.beforeFirst();
        }
}
4

2 回答 2

0

我的结论:

  • 使用 MYSQL:

dbmd.ownDeletesAreVisible(TYPE_SCROLL_INSENSITIVE) RETURNED FALSE: "...如果 ResultSet 对象仍包含已删除的行...则返回 false..."

dbmd.deletesAreDetected(TYPE_SCROLL_INSENSITIVE) RETURNED FALSE: "...如果从 ResultSet 对象中删除的行被删除,则返回 false..."

结果:

ResultSet rs = stmt.executeQuery("select * from book");

printAll(rs); // Prints everything including foo

// deletes foo
while (rs.next()) {
    String title = rs.getString(2);
    if (title.equalsIgnoreCase("foo")) {
        rs.deleteRow();
    }
}

printAll(rs); // Prints everything without foo. Makes no sense.
  • 使用 Apache Derby DB:

dbmd.ownDeletesAreVisible(TYPE_SCROLL_INSENSITIVE) RETURNED TRUE: "...如果删除的行被删除或替换为空行,该方法将返回 true..."

dbmd.deletesAreDetected(TYPE_SCROLL_INSENSITIVE) RETURNED TRUE: "...如果删除的行被空行或无效行替换...该方法将返回 true..."

结果:

ResultSet rs = stmt.executeQuery("select * from book");

printAll(rs); // Prints everything including foo

// deletes foo
while (rs.next()) {
    String title = rs.getString(2);
    if (title.equalsIgnoreCase("foo")) {
        rs.deleteRow();
    }
}

/* Prints 'null' instead of 'foo' here. Now this makes sense */     
printAll(rs);

结论:

这个 MySQL 实现没有正确地遵守 JDBC 规范。上述两种方法相互矛盾,也与输出矛盾。

Apache Derby DB 正确地实现了 JDBC 规范。

于 2016-07-23T23:13:53.887 回答
0

这并不矛盾,JDBC 4.2 规范,第 15.2.4.2 节说(强调我的):

调用该方法后deleteRow,将删除基础数据源中的当前行。如果该行被删除或替换为空行或无效行,则此删除作为打开对象中的更改可见。ResultSet

如果删除的行被删除或替换为空行,则该方法 DatabaseMetaData.ownDeletesAreVisible(int type)将返回true如果对象仍然包含已删除的行,则返回falseResultSet,这意味着删除对于给定类型的 ResultSet 对象的更改是不可见的。

[..]

如果ResultSet对象可以检测到删除,则该ResultSet方法rowDeleted在当前行已被删除时返回 true,在未删除时返回 false。但是,如果 ResultSet 对象无法检测到删除,rowDeleted也会返回false。可以调用该方法DatabaseMetaData.deletesAreDetected(int type)来查看ResultSet指定类型的对象是否可以调用该方法rowDeleted来检测可见的删除。如果从对象中删除了从对象中删除的行,则该方法deletesAreDetected返回,如果删除的行被空行或无效行替换,则返回 true。falseResultSet

它需要在两行之间进行一些阅读(并查看该部分中的示例代码),但这意味着deletesAreDetected 只有在删除可见时才有意义,它辨别删除的可见性:要么该行已被删除(false),要么或替换为空行或无效行 ( true)。

因此,作为ownDeletesAreVisible返回false,结果deletesAreDetected对于“自己的”删除没有任何意义(除了“未检测到删除”);它可能对“其他”删除有意义,但我怀疑当您自己的删除不可见时,其他删除是否可见。

于 2016-07-06T05:55:19.777 回答