繁体   English   中英

Hibernate序列生成器通过共享多个实体而感到困惑

[英]Hibernate sequence generator confused by sharing it for multiple entities

我的班级使用的是ID

@Id @Generated(GenerationTime.INSERT) @GeneratedValue private Integer id;

这适用于H2(支持序列),并通过创建帮助程序表hibernate_sequence解释MySql。 使用这个答案 ,一切都看起来像我想要的方式,特别是对所有表使用单个序列。

有一件事似乎是错误的:帮助程序表中有多行。 我的id@MappedSuperclass声明,在初始化期间, 对于每个具体类,这一行被执行:

insert into hibernate_sequence values ( 1 )

这显然是错误的:每个表都有一行,每个都包含相同的值(最初一个;当更改时,它们都以相同的方式更改,因为SQL update hibernate_sequence set next_val=? where next_val=? ,所以它以相同的方式影响所有行)。

这是无害的,但我想知道:这是一个错误还是我做错了什么?

如果你想让它工作,你现在需要使用其他策略:

@GenericGenerator(
        name = "table_generator",
        strategy = "org.hibernate.id.enhanced.TableGenerator"
)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "table_generator")

那么org.hibernate.id.enhanced.SequenceStyleGenerator

我相信hibernate如何初始化共享单行序列表存在问题。

对于hibernare 5.0.6.Final问题的根源在于org.hibernate.boot.internal.InFlightMetadataCollectorImpl类中

private void processExportableProducers(MetadataBuildingContext buildingContext) {
    // for now we only handle id generators as ExportableProducers

    final Dialect dialect = getDatabase().getJdbcEnvironment().getDialect();
    final String defaultCatalog = extractName( getDatabase().getDefaultNamespace().getName().getCatalog(), dialect );
    final String defaultSchema = extractName( getDatabase().getDefaultNamespace().getName().getSchema(), dialect );

    for ( PersistentClass entityBinding : entityBindingMap.values() ) {
        if ( entityBinding.isInherited() ) {
            continue;
        }

        // ***************************************************************************
        // For Instance, it does not filter out the same entityBinding.getIdentifier()
        // and make initialization multiple time
        // ***************************************************************************
        handleIdentifierValueBinding(
                entityBinding.getIdentifier(),
                dialect,
                defaultCatalog,
                defaultSchema,
                (RootClass) entityBinding
        );
    }

    for ( Collection collection : collectionBindingMap.values() ) {
        if ( !IdentifierCollection.class.isInstance( collection ) ) {
            continue;
        }

        handleIdentifierValueBinding(
                ( (IdentifierCollection) collection ).getIdentifier(),
                dialect,
                defaultCatalog,
                defaultSchema,
                null
        );
    }
}

相同的序列生成器

假设有一个用@MappedSuperclass注释的Base类。 还有A类和B类扩展Base类; 如果注释Id在外地Base带班@SequenceGenerator ,各子类Base共享相同的序列发生器,将increament /数据库它们的ID使用相同的序列 这在当然是无害的,但会导致ids的数字难看:

@MappedSuperclass
public class Person {    
  @Id
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="id_gen")
  @SequenceGenerator(name="id_gen", sequenceName="a_seq", allocationSize=1)
  private Long id;
}

@Entity
public class A extends Base {
}

@Entity
public class B extends Base {
}

这是他们的ids在添加A,然后B,然后A,然后A:

A{id=1, name='...'}
B{id=2, name='...'}
A{id=3, name='...'}

不同的序列生成器

一种更好的方法是为每个表创建一个新的序列 ,可以通过为不同的子类分配不同的序列生成器来实现:

@MappedSuperclass
public class Person {    
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="id_gen")
    private Long id;
}

@Entity
@SequenceGenerator(name="id_gen", sequenceName="a_seq", allocationSize=1)
public class A extends Base {
}

@Entity
@SequenceGenerator(name="id_gen", sequenceName="b_seq", allocationSize=1)
public class B extends Base {
}

在添加A,然后是B,然后是A时,它们的ID将如下所示:

A{id=1, name='...'}
B{id=1, name='...'}
A{id=2, name='...'}

@MappedSuperclass注释的类没有自己的表。 只有继承该类的实体才有表。 因此,根据初始化没有错误,因为,每个具体实体的顺序应该是不同的。 所以这不是一个错误,而是预期的行为。

关于更新,如果在SINGLE表中插入记录时所有三行都得到更新,那么肯定存在错误。 但我不确定这是否是您遇到的情况。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM