【问题标题】:Self referential column may damage H2 database自引用列可能会损坏 H2 数据库
【发布时间】:2011-09-14 23:17:38
【问题描述】:

在您不介意删除的 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. 再次启动数据库并尝试连接。观察错误连接失败:

未找到表“BRICK_H2”; SQL 语句: 创建缓存表 PUBLIC.BRICK_H2( ID TINYINT 默认 IFNULL(((SELECT 最大(ID) 来自 PUBLIC.BRICK_H2 /* PUBLIC.BRICK_H2.tableScan */ 更新) + 1), 0) ) [42102-155] 42S02/42102 (帮助)

顺便说一句。请不要回复“使用auto_increment”。是的,我知道auto_increment 列。自动增量列在回滚后会留下间隙,并且不处理所有数据类型。例如,如果应用程序使用一种不是“添加常量整数”的算法,如何自动增加一列?此外,没有办法将auto_incrementVARCHAR 相似,但您的应用程序可能有一个完全合理的概念。

【问题讨论】:

  • 我想问题是“如何在不破坏数据库的情况下获得相同的行为?”* - 因为否则这是一个错误报告,而不是 StackOverflow 问题。

标签: database h2


【解决方案1】:

一种解决方法是使用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' 是相对的……您仍然可以使用恢复工具检索数据。但当然它不是很好,并且将在下一个版本中修复。问题是 H2 不限制您在默认子句中可以执行的操作。其他数据库根本不允许在默认子句中进行任何查询,但我认为这很胆小(这是正确的词吗?),我会尝试找到更好的解决方案(可能允许它)。你有什么建议?

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2018-08-30
  • 1970-01-01
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-19
  • 2017-10-28
相关资源
最近更新 更多