自引用列可能会损坏H2数据库

时间:2011-06-14 18:59:39

标签: database h2

在您不介意删除的H2DB上尝试以下操作。 警告。这会对数据库造成不可破坏的损害!

  1. 使用自引用默认列创建表。例如,使用alter table修改普通表:

    create table if not exists BRICK_H2( ID tinyint );
    alter table BRICK_H2 alter column ID set default ifnull(
        (select max(ID) from BRICK_H2 for update)+1,0
    );
    
  2. 关闭连接并关闭数据库。

  3. 再次启动数据库并尝试连接。错误时观察连接失败:

  4. Table "BRICK_H2" not found; SQL statement:
    CREATE CACHED TABLE PUBLIC.BRICK_H2(
        ID TINYINT DEFAULT IFNULL(((SELECT
        MAX(ID)
    FROM PUBLIC.BRICK_H2
        /* PUBLIC.BRICK_H2.tableScan */
    FOR UPDATE) + 1), 0)
    ) [42102-155] 42S02/42102 (Help)
    

    顺便说一句。请不要回复“使用auto_increment”。是的,我知道auto_increment列。回滚后自动增量列留下间隙,不处理所有数据类型。例如,如何自动递增应用程序使用不是“添加常量整数?”的算法的列。此外,没有办法auto_increment一个VARCHAR,但你的应用程序可能有一个非常明智的概念。

1 个答案:

答案 0 :(得分:3)

解决方案是使用Java函数,例如:

drop all objects;
create table if not exists do_not_brick(id int);
create alias query as $$
String query(Connection conn, String sql) throws SQLException { 
  ResultSet rs = conn.createStatement().executeQuery(sql); 
  rs.next(); 
  return rs.getString(1);
}$$;
alter table do_not_brick alter column id set default
ifnull(query('select max(id) from do_not_brick for update')+1, 0);
insert into do_not_brick() values(), (), ();
select * from do_not_brick;

顺便说一下,'brick'是相对的...你仍然可以使用Recover工具检索数据。但当然它并不好,并将在下一个版本中修复。问题是H2不限制你在default子句中可以做的事情。其他数据库根本不允许在default子句中进行任何查询,但我认为这是胆小的(这是正确的词吗?),我会尝试找到更好的解决方案(可能允许它)。你有什么建议?