h2 索引损坏?加载了 runscript 的嵌入式数据库有 "invisible"行

标签 h2

在嵌入模式下使用 h2,我正在从先前由 h2 使用 SCRIPT 命令生成的脚本备份恢复内存数据库。

我使用这个网址:

jdbc:h2:mem:main

我这样做:

FileReader script = new FileReader("db.sql");
RunScript.execute(conn,script);

根据文档,它应该类似于此 SQL:

RUNSCRIPT FROM 'db.sql'

而且,在我的应用程序中,它们确实执行相同的操作。但是,如果我使用 h2.bat 使用 Web 控制台运行负载,则会得到不同的结果。

在我的应用程序中加载此数据后,我知道有些行已加载,但我无法通过查询访问。这些查询证明了这一点:

select count(*) from MY_TABLE yields 96576
select count(*) from MY_TABLE where ID <> 3238396 yields 96575
select count(*) from MY_TABLE where ID = 3238396 yields 0

加载 Web 控制台并使用相同的 RUNSCRIPT 命令和文件加载会生成一个数据库,我可以在其中找到具有该 ID 的行。

我的第一 react 是我正在处理某种锁定问题。我尝试了以下方法(结果没有变化):

  1. 在 RunScript.execute() 之后手动发出 conn.commit()
  2. 将 ;LOCK_MODE=3 和 ;LOCK_MODE=0 附加到我的网址

有任何关于如何识别正在发生的事情的正确方向的指针吗?我最终插入:

Server.createWebServer("-trace","-webPort","9083").start()

这样我就可以通过 Web 控制台运行这些查询来检查通过 JDBC 返回的内容。该问题在我的应用程序中始终发生,并且始终不会通过网络控制台发生。所以一定有什么东西在起作用。

表模式并不奇特。这是来自

的架构列
select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME='MY_TABLE'

CREATE MEMORY TABLE PUBLIC.MY_TABLE(
   ID INTEGER SELECTIVITY 100,
   P_ID INTEGER SELECTIVITY 4,
   TYPE VARCHAR(10) SELECTIVITY 1,
   P_ORDER DECIMAL(8, 0) SELECTIVITY 11,
   E_GROUP INTEGER SELECTIVITY 1,
   P_USAGE VARCHAR(16) SELECTIVITY 1
)

任何朝正确方向的插入都将受到非常赞赏。

编辑

因此,在运行 RunScript 命令加载数据库后,数据库似乎以某种方式损坏了。当我试图调试以找出发生了什么时,我尝试执行以下命令:

delete from MY_TABLE where ID <> 3238396

我最终得到:

Row not found when trying to delete from index "PUBLIC.MY_TABLE_IX1: 95326", SQL statement:
delete from MY_TABLE where ID <> 3238396 [90112-178] 90112/90112 (Help)

然后,我尝试从上下文中删除并重新创建所有索引,但这对整体问题没有影响。

救命!

编辑2

更多信息:该问题是由于创建索引而发生的。 (我相信我在 h2 中发现了一个错误,并且我正在努力创建一个重现它的最小案例)。如果您有正确的数据集,下面的简单代码将重现该问题。

public static void main(String[] args)
{
      try
      {
             final String DB_H2URL = "jdbc:h2:mem:main;LOCK_MODE=3";
             Class.forName("org.h2.Driver");
             Connection c = DriverManager.getConnection(DB_H2URL, "sa", "");
             FileReader script = new FileReader("db.sql");
             RunScript.execute(c,script);
             script.close();
             Statement st = c.createStatement();
             ResultSet rs = st.executeQuery("select count(*) from MY_TABLE where P_ID = 3238396");
             rs.next();
             if(rs.getLong(1) == 0)
                   System.err.println("It happened");
             else
                   System.err.println("It didn't happen");
      } catch (Throwable e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
      }
}

我已将 db.sql 脚本减少到大约 5000 行,但这种情况仍然发生。当我尝试达到 2500 行时,它停止了。如果我删除 db.sql 的最后一行(这是索引创建),问题也将停止发生。最后一行是这样的:

CREATE INDEX PUBLIC.MY_TABLE_IX1 ON PUBLIC.MY_TABLE(P_ID);

但数据在这方面发挥着重要作用。它似乎仍然只是一行,并且索引以某种方式使其无法访问。

编辑3

我已经确定了要重现的最小数据示例。我将表模式剥离为单个列,我发现该列中的值似乎并不重要——只是行数。这是通过 SCRIPT 命令生成的 db.sql 的内容(用明显的内容进行了剪裁):

;            
CREATE USER IF NOT EXISTS SA SALT '8eed806dbbd1ea59' HASH '6d55cf715c56f4ca392aca7389da216a97ae8c9785de5d071b49de5436b0c003' ADMIN;          
CREATE MEMORY TABLE PUBLIC.MY_TABLE(
    P_ID INTEGER SELECTIVITY 100
);   
-- 5132 +/- SELECT COUNT(*) FROM PUBLIC.MY_TABLE;            
INSERT INTO PUBLIC.MY_TABLE(P_ID) VALUES
(1),
(2),
(3),
...  snipped you obviously have breaks in the bulk insert here ...
(5143),
(3238396);    
CREATE INDEX PUBLIC.MY_TABLE_IX1 ON PUBLIC.MY_TABLE(P_ID);

但这会重现问题。 [请注意,每次有批量插入行时,我的编号都会跳过一个数字。所以确实有 5132 行,尽管您看到 5143 select count(*) from MY_TABLE 产生 5132]。另外,我现在似乎可以通过执行以下操作直接在 WebConsole 中重新创建问题:

drop table MY_TABLE
runscript from 'db.sql'
select count(*) from MY_TABLE where P_ID = 3238396

如果当您知道其中有一行时从选择中返回 0,则您已经重新创建了问题。

奇怪的是,我似乎能够做到

select * from MY_TABLE order by P_ID desc

此时我可以看到该行。但直接进入行:

select * from MY_TABLE where P_ID = 3238396

没有任何结果。

我刚刚意识到我应该注意我正在使用h2-1.4.178.jar

最佳答案

h2 人员显然已经解决了这个问题。

https://code.google.com/p/h2database/issues/detail?id=566

只需从版本控制获取代码或等待下一个版本构建。谢谢托马斯。

关于h2 索引损坏?加载了 runscript 的嵌入式数据库有 "invisible"行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24267914/

相关文章:

sql - 依赖于另一个字段的自动递增字段

java - 如何让jOOQ生成不引用主键的复合外键?

sql - H2 数据库错误 未知数据类型 INTERVAL

sql - H2 TRUNC 功能缺陷

java - H2 内存DB在MySQL模式下对ORDER BY的处理方式不同

java - org.h2.jdbc.JdbcSQLException : General error: "java.lang.StackOverflowError" [50000-176]

jdbc - Play Framework : Error getting sequence nextval using H2 in-memory database

date - spring boot 测试 h2 data.sql 语言环境日期格式错误

h2 - 无法浏览 H2 数据库文件?

scala - 在 SBT 下运行 H2 时包不存在