使用 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