【问题标题】:Hibernate 4 to 5 migration with existing @TableGenerator使用现有 @TableGenerator 进行 Hibernate 4 到 5 迁移
【发布时间】:2020-07-17 13:13:11
【问题描述】:

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

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

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

我找到的所有干净的解决方案都是基于 Hibernate 4 之前在 AUTO 模式下使用的想法 (@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/

【问题讨论】:

    标签: hibernate migration


    【解决方案1】:

    假设您有以下映射:

    @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.TableGeneratorpooled-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 (pooled-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 中提到的所有表,并将@TableGenerator.valueColumnName 字段的值手动更新为max(id) + 1。 例如,就我而言,我应该运行以下 sql:

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

    附:也许thisSteve Ebersole 的文章也会有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-18
      • 2016-06-25
      • 1970-01-01
      • 2022-12-12
      • 1970-01-01
      • 2017-02-10
      • 2013-11-10
      • 2019-02-25
      相关资源
      最近更新 更多