首页 > 解决方案 > 使用现有 @TableGenerator 进行 Hibernate 4 到 5 迁移

问题描述

我们从 Hibernate 4 迁移到 5,一个主要问题是新的生成器,它为表行生成 ID。我们的旧生成器都是基于表的,比如

@TableGenerator(name = TABLE_NAME + "_generator", table = ...)
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;

Hibernate 5 中的新默认生成器不正确地尊重这一点,并看似“从头开始”生成新的 id,因此在插入新行时会出现“Already existing ID”异常。

我发现的所有干净解决方案都是基于 Hibernate 4 以前在 AUTO-Mode ( @GeneratedValue(strategy = GenerationType.AUTO)) 中使用的想法,但我们始终使用GenerationType.TABLE.

“肮脏”的解决方案:添加<property name="hibernate.id.new_generator_mappings" value="false"/>到 Hibernates persistence.xml。结果:我们现有的数据库可以毫无问题地使用,除了:来自 Hibernate 的持续警告

HHH90000015: Found use of deprecated [org.hibernate.id.MultipleHiLoPerTableGenerator] table-based id generator; use org.hibernate.id.enhanced.TableGenerator instead.  See Hibernate Domain Model Mapping Guide for details.]]

我的问题是:我们如何才能保留原始数据库,停止使用已弃用的代码,并正确创建具有新 ID 的新行,而不与现有 ID 冲突?

特别是因为据说 Hibernates 5 池标识符生成器比表更好: https ://vladmihalcea.com/hibernate-hidden-gem-the-pooled-lo-optimizer/

标签: hibernatemigration

解决方案


假设您有以下映射:

@Entity
@Table(name = "TST_PATIENT_ENT")
public class Patient
{
   @Id
   @GeneratedValue(strategy = GenerationType.TABLE, generator = "table-generator")
   @TableGenerator(
      name =  "table-generator",
      table = "TST_TABLE_IDENTIFIER",
      pkColumnName = "table_name",
      valueColumnName = "product_id",
      allocationSize = 3
   )
   @Column(name = "pat_id")
   private Long id;
   // ...
}

现在让我们看看基于旧样式表的 ID 生成 ( org.hibernate.id.MultipleHiLoPerTableGenerator) 和新样式 ( org.hibernate.id.enhanced.TableGeneratorwith pooled-lo, pooled) 之间的区别:

  1. MultipleHiLoPerTableGenerator(maxLo = allocationSize - 1)
Inserted IDs   |  Last seq val   |   Count of inserted rows
-----------------------------------------------------------
 1             |      1          |          1
 3, 4          |      2          |          2
 6 .. 8        |      3          |          3
 9 .. 12       |      5          |          4
 15 .. 19      |      7          |          5
  1. org.hibernate.id.enhanced.TableGenerator(汇集-lo)
Inserted IDs   |  Last seq val   |   Count of inserted rows
-----------------------------------------------------------
 1             |      3          |          1
 4, 5          |      6          |          2
 7 .. 9        |      9          |          3
 10 .. 13      |      15         |          4
 16 .. 20      |      21         |          5
  1. org.hibernate.id.enhanced.TableGenerator(汇集)
Inserted IDs   |  Last seq val   |   Count of inserted rows
-----------------------------------------------------------
 1             |      6          |          1
 5, 6          |      9          |          2
 8.. 10        |      12         |          3
 11 .. 14      |      18         |          4
 17 .. 21      |      24         |          5

价值在哪里Last seq val

select product_id from TST_TABLE_IDENTIFIER where table_name = 'TST_PATIENT_ENT';

在每行插入之后。

因此,如果您决定使用以下配置:

<property name="hibernate.id.new_generator_mappings">true</property>
<property name="hibernate.id.optimizer.pooled.preferred">pooled-lo</property>

您应该查看 中提到的所有表,并将字段的@TableGenerator.table值手动更新为. 例如,就我而言,我应该运行以下 sql:@TableGenerator.valueColumnNamemax(id) + 1

update TST_TABLE_IDENTIFIER
set product_id = (select max(pat_id) + 1 from TST_PATIENT_ENT)
where table_name = 'TST_PATIENT_ENT';

PS 也许这篇Steve Ebersole 的文章也会很有用。


推荐阅读