Liquibase:使用modifyDataType重构H2数据库,将INT型自动递增列改为BIGINT型



我有一个主键列,这是一个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, AbstractBaseEvent在代码中定义了以下Hibernate映射:

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

几点说明:

  • hibernate映射在重构数据类型
  • 之前工作
  • Liquibase版本为2.0.1
  • 是否适用于MySQL尚未测试

我测试了(Hibernate 3.6.2)。最后,H2 1.3.160,方言:org.hibernate.dialect.H2Dialect)你的情况是什么:

  • 当GenerationType为AUTO, data type为INT时,实际生成
  • 当GenerationType为AUTO且数据类型为BIGINT时,为实际值生成类型为IDENTITY。因此,如果id-field是,则此操作将失败定义为ID BIGINT PRIMARY KEY,而不是ID BIGINT IDENTITY(在这里添加PRIMARY KEY和H2是多余的)。

你能做的:

如果您希望实际的生成类型为SEQUENCE,那么

@GeneratedValue(strategy = GenerationType.SEQUENCE)

似乎有效。序列本身不需要更改,因为根据文档类型是BIGINT。我会这样做,因为这样就没有什么变化了,而且序列的生成方式也很清楚

另一种可能性是将列定义为具有startValue的IDENTITY(因为可能存在值)并使用GenerationType。AUTO和以前一样。

这是一个老问题,公认的答案有很好的分析但是我遇到了同样的问题,花了3个小时才找到真正的问题和解决方案,所以值得把它留在这里供将来参考。

所以真正的问题是在液体基础上这句话

<changeSet id="1" author="trond">
    <modifyDataType tableName="event" columnName="id" newDataType="BIGINT" />
    <rollback>
        <modifyDataType tableName="event" columnName="id" newDataType="INT" />
    </rollback>
</changeSet>`

正在生成alter查询

ALTER TABLE event ALTER COLUMN id BIGINT

从H2

的id列中删除默认的序列值

因此,当您尝试插入新行时,id为空,从而抛出SQL错误。

不幸的是,ALTER列的行为因数据库供应商而异,所以最好的解决方案可能是为测试(H2)和生产(MySQL)创建不同的迁移更改日志

和H2你可以使id auto_increment在modifyDataType更改后再次

<addAutoIncrement
    columnDataType="bigint"
    columnName="id"
    incrementBy="1"
    startWith="1"
    tableName="event"/>
</changeSet>`

我首先将您的@GenerationType更改为特定的东西(如IDENTITY),以排除Hibernate从序列中获取奇怪值的任何问题。或者完全删除。

你的重构看起来很好,我看不出有什么明显的问题。

当涉及到引号标识符时,H2和Liquibase通常不能很好地配合;Liquibase中的H2数据库类引用了一些,而不引用其他的。也许案子转换把你搞砸了?

EclipseLink有时会有问题,当一个基本类型是0(!),因为它有时会把这样的值作为null或未初始化,但据我所知,Hibernate没有这个限制。

我知道这不是一个真正的答案,但希望能让你指向正确的方向。

相关内容

  • 没有找到相关文章

最新更新