DatabaseMetaData.ownDeletesAreVisible vs DatabaseMetaData.deletesAreDetected Controversy

时间:2016-07-05 23:12:12

标签: java mysql jdbc database-metadata

我正在使用JDBC和mysql-connector-java-6.0.2.jar,除非我做错了什么,我认为DatabaseMetaData.ownDeletesAreVisible和DatabaseMetaData.deletesAreDetected实现在某种程度上彼此不一致。

这里有关于ownDeletesAreVisible的JDBC规范:

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

关于deletesAreDetected:

" ...方法deletesAreDetected返回false,如果从ResultSet对象中删除了一行,如果删除的行被空行或无效行替换,则返回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();
        }
}

2 个答案:

答案 0 :(得分:0)

这不是一个矛盾,JDBC 4.2 specification,第15.2.4.2节说(强调我的):

  

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

     

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

     

[..]

     

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

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

因此,当ownDeletesAreVisible返回false时,deletesAreDetected的结果对于自己的&#39}没有任何意义。删除(除了'删除未被检测到');它可能对其他人有意义。删除,但我怀疑当你自己没有删除时,其他删除是可见的。

答案 1 :(得分:0)

我的结论:

  • 使用MYSQL:

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

dbmd.deletesAreDetected(TYPE_SCROLL_INSENSITIVE)返回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规范。