Liquibase与PostgreSQL 10以下版本兼容性问题:serial与identity列
PostgreSQL bigserial 与 Identity 列的兼容问题
问题背景
我通过以下配置定义数据库列:
<column name="id" type="bigserial"> <constraints primaryKey="true"/> </column>
该配置在PostgreSQL 9.x版本中会生成独立序列及带默认值的列,但在PostgreSQL 15版本中生成的SQL语句变为:
id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL
技术问题与解答
1. 如何让该配置在所有PostgreSQL版本中都保持bigserial的行为?
- 显式拆分序列与列的配置,替代
bigserial的隐式映射:- 单独定义序列:
<sequence name="id_seq" startValue="1" incrementBy="1"/> - 将列类型改为
bigint,手动绑定序列的nextval作为默认值,同时保留主键约束:
这种写法在所有PostgreSQL版本中都会生成「独立序列+带默认值的bigint列」,完全匹配传统<column name="id" type="bigint" defaultValue="nextval('id_seq')"> <constraints primaryKey="true" nullable="false"/> </column>bigserial的行为。
- 单独定义序列:
- 如果使用Hibernate等ORM框架,可以在实体类上通过
@SequenceGenerator和@GeneratedValue(strategy = GenerationType.SEQUENCE)注解强制指定序列生成策略,避开不同PostgreSQL版本对bigserial的映射差异。
2. 能否不修改变更日志就将其恢复为bigserial?
可以,直接操作数据库元数据即可:
- 先创建符合
bigserial默认规则的序列(命名格式通常为表名_id_seq):CREATE SEQUENCE 表名_id_seq OWNED BY 表名.id; - 修改列的默认值为序列的
nextval:ALTER TABLE 表名 ALTER COLUMN id SET DEFAULT nextval('表名_id_seq'); - 移除列的identity属性:
整个过程无需修改现有变更日志,直接在数据库端执行上述SQL就能将列恢复为ALTER TABLE 表名 ALTER COLUMN id DROP IDENTITY IF EXISTS;bigserial的等效状态。
3. 在Spring Boot中需使用序列实现批量插入时,identity列有哪些优势?
- 原生批量ID返回支持:PostgreSQL的identity列支持
INSERT ... RETURNING语法批量返回生成的ID,Spring Data JPA或JDBC模板可直接利用该特性,无需手动预取序列值再插入,代码更简洁。 - 事务安全无空洞:identity列的ID生成由数据库事务管理,不会出现手动预取序列值后事务回滚导致的序列空洞问题。
- ORM优化更成熟:Spring Boot搭配的新版本Hibernate对PostgreSQL identity列的批量插入性能优化已接近序列方式,兼容性更好。
- 减少对象维护成本:identity列的序列由数据库自动管理,无需手动创建、绑定序列对象,降低了数据库元数据的维护工作量。
内容的提问来源于stack exchange,提问作者NightCity10932
相关产品推荐
相关产品推荐

