4

My classes use an ID like

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

This works perfectly for H2 (supporting sequences) and gets interpreted for MySql by creating a helper table hibernate_sequence. Using this answer, everything looks the way I want, especially using a single sequence for all tables.

One thing seems to be wrong: There are multiple rows in the helper table. My id is declared in a @MappedSuperclass and during initialization, for each concrete class this line gets executed:

insert into hibernate_sequence values ( 1 )

This is obviously wrong: there is a line per table there and each contains the same value (initially one; when changed, they all change in the same way, as the SQL is update hibernate_sequence set next_val=? where next_val=?, so it effects all the rows in the same way).

It's harmless, but I wonder: Is it a bug or am I doing something wrong?

Community
  • 1
  • 1
maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • I deleted my answer; I did not understand your issue properly. I think that you should edit the question to include the explanation you provided in the comment of my answer. – Dragan Bozanovic Jan 07 '16 at 20:33

3 Answers3

4

If you want to make it works you need to use other strategy for now:

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

What about org.hibernate.id.enhanced.SequenceStyleGenerator:

I believe there is an issue in how hibernate initializes shared single row sequence table.

For hibernare 5.0.6.Final Source of the issue lies in org.hibernate.boot.internal.InFlightMetadataCollectorImpl class in

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
        );
    }
}
valery.barysok
  • 604
  • 4
  • 13
  • You start with "to make it work", which sounds wrong (as it does work now, it's just not nice) and confused me while quickly scanning your answer. But you seem to be right. I filed [HHH-10441](https://hibernate.atlassian.net/browse/HHH-10441?jql=project%20%3D%20HHH) and linked it to your answer. – maaartinus Jan 14 '16 at 17:01
4

Same Sequence Generator

Presume there is a Base class annotated with @MappedSuperclass. There are also A and B classes extending Base class; If you annotate Id field in Base class with @SequenceGenerator, all subclasses of Base share the same sequence generator and will increament/use the same sequence in the database for their ids. This is ofcourse harmless but results in ugly numbers for 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 {
}

This is what their ids look like after adding A, then B, then A :

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

Distinct Sequence Generator

A nicer way would be having a fresh sequence for each table which can be implemented through assigning different sequence generators for different subclasses :

@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 {
}

Their ids will look like this after adding A, then B, then A :

A{id=1, name='...'}
B{id=1, name='...'}
A{id=2, name='...'}
NiMa Thr
  • 458
  • 3
  • 12
  • 1
    This question about why helper table is initialized multiple times for shared sequence with `org.hibernate.id.enhanced.SequenceStyleGenerator` strategy. – valery.barysok Jan 13 '16 at 05:25
0

A class annotated with @MappedSuperclass has no table of it's own. Only the entities that inherit that class have tables. So according to that the initialization has no bug, because, the sequence should be different for each concrete entity. So this is not a bug, rather it's the expected behavior.

Regarding update, if all three rows get updated when you insert a record in a SINGLE table then there is definitely a bug. But I am not sure if this is the scenario that you are experiencing.

James
  • 2,756
  • 17
  • 19
  • There's nothing but the single column `next_val` in `hibernate_sequence`, so there's no way to assign different rows to different concrete classes. Indeed, all three rows get updated when I insert a record in a single table. – maaartinus Jan 09 '16 at 21:09
  • I disagree about expected behaviour because it is one sequence for all tables that you want. If you will use some native sequence it will be work as one for many. So obviously here we have wrong initialization of sequence implemented as the table. – valery.barysok Jan 12 '16 at 15:47