使用 ALTER TABLE 添加新列后 H2 数据库插入数据异常

Posted

技术标签:

【中文标题】使用 ALTER TABLE 添加新列后 H2 数据库插入数据异常【英文标题】:H2 database inserting data exception after adding new column with ALTER TABLE 【发布时间】:2013-11-04 09:37:40 【问题描述】:

我正在向表中添加新列,如下代码:

    String sql = "ALTER TABLE PROJE_ALAN ADD NEWCOLUMN VARCHAR(30)";
    PreparedStatement ps = conn.prepareStatement(sql.toString());
    ps.execute();
    conn.close();
    ps.close();

这是在我的表中添加一个新列,但是当我想添加新数据时会引发异常:

    Caused by: org.h2.jdbc.JdbcSQLException: General error: "net.sourceforge.hatbox.RTreeInternalException: Unable to select meta node"; SQL statement: INSERT INTO "PROJE_ALAN" ( "THE_GEOM","JJ","KK","NEWCOLUMN" ) VALUES ( ST_GeomFromText ('MULTIPOLYGON (((-244856.06897661195 4166022.019422841, 189248.78294214187 4442270.561552957, 778743.439809086 4301679.785647452, 662817.7123080553 4101892.893571207, 83189.0748029009 3707252.1190996123, -244856.06897661195 4166022.019422841)))',23036),'','','') [50000-172]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:158)
at org.h2.message.DbException.convert(DbException.java:281)
at org.h2.schema.TriggerObject.fireRow(TriggerObject.java:215)
at org.h2.table.Table.fireRow(Table.java:904)
at org.h2.table.Table.fireAfterRow(Table.java:895)
at org.h2.command.dml.Insert.insertRows(Insert.java:128)
at org.h2.command.dml.Insert.update(Insert.java:86)
at org.h2.command.CommandContainer.update(CommandContainer.java:79)
at org.h2.command.Command.executeUpdate(Command.java:235)
at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:180)
at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:155)
at org.apache.commons.dbcp.DelegatingStatement.execute(DelegatingStatement.java:264)
at org.apache.commons.dbcp.DelegatingStatement.execute(DelegatingStatement.java:264)
at org.geotools.jdbc.JDBCDataStore.insert(JDBCDataStore.java:1447)
... 17 more

    Caused by: net.sourceforge.hatbox.RTreeInternalException: Unable to select meta node
at net.sourceforge.hatbox.Lock.<init>(Lock.java:88)
at net.sourceforge.hatbox.RTreeSessionDb.<init>(RTreeSessionDb.java:75)
at net.sourceforge.hatbox.jts.InsertTrigger.fire(InsertTrigger.java:43)
at org.h2.schema.TriggerObject.fireRow(TriggerObject.java:201)
... 28 more

    Caused by: org.h2.jdbc.JdbcSQLException: Table "PROJE_ALAN_COPY_11_5_HATBOX" not found; SQL statement: select node_data, id from "PUBLIC"."PROJE_ALAN_COPY_11_5_HATBOX" where id = ? FOR UPDATE [42102-172]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:169)
at org.h2.message.DbException.get(DbException.java:146)
at org.h2.schema.Schema.getTableOrView(Schema.java:419)
at org.h2.command.Parser.readTableOrView(Parser.java:4808)
at org.h2.command.Parser.readTableFilter(Parser.java:1099)
at org.h2.command.Parser.parseSelectSimpleFromPart(Parser.java:1705)
at org.h2.command.Parser.parseSelectSimple(Parser.java:1813)
at org.h2.command.Parser.parseSelectSub(Parser.java:1699)
at org.h2.command.Parser.parseSelectUnion(Parser.java:1542)
at org.h2.command.Parser.parseSelect(Parser.java:1530)
at org.h2.command.Parser.parsePrepared(Parser.java:405)
at org.h2.command.Parser.parse(Parser.java:279)
at org.h2.command.Parser.parse(Parser.java:251)
at org.h2.command.Parser.prepareCommand(Parser.java:218)
at org.h2.engine.Session.prepareLocal(Session.java:425)
at org.h2.engine.Session.prepareCommand(Session.java:374)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1138)
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:70)
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:644)
at net.sourceforge.hatbox.Lock.<init>(Lock.java:72)
... 31 more

如果我重新启动我的应用程序,那么我可以将新数据添加到新表中。我认为问题可能是在不重新启动应用程序的情况下刷新索引。可能和帽子盒有关。

那么我错过了什么?

【问题讨论】:

找不到表通常意味着您使用的是不同的数据库。您的数据库 URL 是什么?您能否使用数据库文件的绝对路径,例如jdbc:h2:/data/test。确保您没有使用相对路径,例如 jdbc:h2:test 我正在使用数据库文件的绝对路径。如果我在添加新列后重新启动我的应用程序,没有问题但没有关闭应用程序会引发异常。重命名任何列也没有任何问题 好的,我明白了,所以它不是数据库 URL。表名PROJE_ALAN_COPY_9_0_HATBOX很奇怪,貌似是临时表名;修改一个表会先创建一个临时表,然后重命名它,但是后缀_HATBOX 很奇怪——你知道帽子盒是否使用了特殊的“表引擎”(即不是普通的 H2 表)吗? 嗯,我看到后缀_HATBOX是Hatbox工具添加的。表名PROJE_ALAN_COPY_9_0 只是一个临时名称,它永远不会对工具或应用程序可见。我猜这是因为帽子盒触发器在复制数据时看到了这个临时表......您能否发布完整的堆栈跟踪(如果有更多)? 嗯,我不太确定,但我认为问题在于 Hatbox 创建触发器的方式。由于某种原因,临时表上似乎有一个触发器。我想有可能在 Hatbox 中解决这个问题,但我自己不了解 Hatbox,所以我无能为力。添加列后重新打开数据库是否有效?这对您来说是一种可能的解决方法吗? 【参考方案1】:

这不是 Hatbox 的错。这是H2中的一个错误。 H2 引擎在 ALTER TABLE 语句之后重新创建触发器,但使用 TEMP TABLE NAME 调用 trigger.init。因此,触发器正在使用错误的表名进行初始化。创建触发器后,H2 将表重命名为原始值。

我对这个错误的解决方法是(它也有问题,但有效):

将 net.sourceforge.hatbox.jts.Insert、Update、Delete 触发器初始化方法更改为

public void init(Connection con, String schema, String trigger, String table,
        boolean before, int type) throws SQLException 

    this.schema = schema;
    this.table = table;

    if(this.table.contains("_COPY_")) 
        this.table = table.substring(0, table.indexOf("_COPY_"));
    

你必须在使用这个的时候,如果你的表名上有COPY,它就不起作用了。您可以将_COPY_ 更改为*_COPY_?_?,如正则表达式匹配。

【讨论】:

以上是关于使用 ALTER TABLE 添加新列后 H2 数据库插入数据异常的主要内容,如果未能解决你的问题,请参考以下文章

sql [ALTER TABLE ADD COLUMN]将新列添加到现有表#SQL

在 IMPALA/HIVE 中添加带有 SELECT 的新列后,旧表数据变为 NULL

使用流式 API 更新新列后无法向 BigQuery 表插入新值

ALTER添加列后,立即UPDATE该列会报错

SQL语句怎么加列

Mysql下在某一列后即表的某一位置添加新列的sql语句