我有一个主键列,它是一个INT列,我想将其更改为BIGINT。我们的测试和生产环境使用MySQL,但对于单元测试,我们使用嵌入式H2数据库。
我创建了以下Liquibase重构:
...
<changeSet id="1" author="trond">
<modifyDataType tableName="event" columnName="id" newDataType="BIGINT" />
<rollback>
<modifyDataType tableName="event" columnName="id" newDataType="INT" />
</rollback>
</changeSet>
...
重构有效,但是当我尝试使用Hibernate将对象持久化到数据库时,我收到以下错误消息(我已经包装了错误消息):
ERROR org.hibernate.util.JDBCExceptionReporter [main]: NULL not allowed for column "ID";
SQL statement: insert into event (id, eventtime, guid, meta, objectguid, originatorid, subtype, type) values (null, ?, ?, ?, ?, ?, ?, '0') [90006-140]
JDBC exception on Hibernate data access:
SQLException for SQL [insert into event (id, eventtime, guid, meta, objectguid, originatorid, subtype, type) values (null, ?, ?, ?, ?, ?, ?, '0')];
SQL state [90006]; error code [90006]; could not insert: [event.MyEvent];
nested exception is org.hibernate.exception.GenericJDBCException: could not insert: [event.MyEvent]
MyEvent类继承自AbstractBaseEvent,它在代码中定义了以下Hibernate映射:
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
几点:
答案 0 :(得分:6)
我测试了(Hibernate 3.6.2.Final,H2 1.3.160,dialect:org.hibernate.dialect.H2Dialect)你的案例中发生了什么:
你能做什么:
如果您希望实际生成类型为SEQUENCE,那么
@GeneratedValue(strategy = GenerationType.SEQUENCE)
似乎有效。序列本身不需要进行任何更改,因为无论如何,documentation类型都是BIGINT。我会这样做,因为那时没有什么真正改变,并且很清楚生成序列的方式
其他可能性是使用startValue将列定义为IDENTITY(因为可能存在的值),并像以前一样使用GenerationType.AUTO。
答案 1 :(得分:1)
我首先会将您的@GenerationType
更改为特定的内容(例如IDENTITY
),以排除Hibernate从序列中获取奇怪值的任何问题。或者完全删除它。
你的重构看起来很好,我看不出任何明显的问题。
当引用标识符时,H2和Liquibase通常不能很好地协同工作; Liquibase中的H2数据库类引用了一些,并没有引用其他类。案件转换可能让你搞砸了吗? 当原始类型为0
(!)时,EclipseLink有时会出现问题,因为它有时会将这样的值视为null
或未初始化,但据我所知,Hibernate不会受到此限制。< / p>
我知道,这不是一个真正的答案,但希望能让你指出正确的方向。
答案 2 :(得分:1)
这是一个老问题,接受的答案有很好的分析 但我遇到了同样的问题,花了3个小时才找到真正的问题和解决方案,因此将其留在这里以供将来参考。
所以真正的问题是liquibase 这句话
<changeSet id="1" author="trond">
<modifyDataType tableName="event" columnName="id" newDataType="BIGINT" />
<rollback>
<modifyDataType tableName="event" columnName="id" newDataType="INT" />
</rollback>
</changeSet>
正在产生这个 改变查询
ALTER TABLE event ALTER COLUMN id BIGINT
从id列
中删除默认序列值因此,当您尝试插入新行时,id为null,因此抛出了sql错误。
不幸的是,ALTER列的行为因数据库供应商而异,因此最好的解决方案可能是为测试(H2)和生产(mysql)创建不同的迁移更改日志
并且在H2上,您可以在modifyDataType更改
后再次进行id auto_increment <addAutoIncrement
columnDataType="bigint"
columnName="id"
incrementBy="1"
startWith="1"
tableName="event"/>
</changeSet>