How to write a custom sequence-based String Id generator with JPA and Hibernate

i am new to hibernate. i was trying to create custom id of type string using hibernate and mysql. can someone help me with how to override generator class?

here is my hbm file

<class name="com.usermanagement.model.Employee" table="EMPLOYEE">
    <id name="id" column= "ID">
	<generator class="com.customid.EmployeeIdGenerator"/>
    </generator>
    </id>
    <property name="name" type="java.lang.String">
        <column name="NAME" />
    </property>
</class>

The id i am trying to generate is like str001, str002, str003…

You can write a String identifier generator like this one:

public class StringSequenceIdentifier implements 
        IdentifierGenerator, Configurable {

    public static final String SEQUENCE_PREFIX = "sequence_prefix";

    private String sequencePrefix;

    private String sequenceCallSyntax;

    @Override
    public void configure(
            Type type,
            Properties params,
            ServiceRegistry serviceRegistry)
        throws MappingException {

        final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService(
                JdbcEnvironment.class
        );

        final Dialect dialect = jdbcEnvironment.getDialect();

        final ConfigurationService configurationService = serviceRegistry.getService(
                ConfigurationService.class
        );

        String globalEntityIdentifierPrefix = configurationService.getSetting(
            "entity.identifier.prefix",
            String.class,
            "SEQ_"
        );

        sequencePrefix = ConfigurationHelper.getString(
            SEQUENCE_PREFIX,
            params,
            globalEntityIdentifierPrefix
        );

        final String sequencePerEntitySuffix = ConfigurationHelper.getString(
            SequenceStyleGenerator.CONFIG_SEQUENCE_PER_ENTITY_SUFFIX,
            params,
            SequenceStyleGenerator.DEF_SEQUENCE_SUFFIX
        );

        boolean preferSequencePerEntity = ConfigurationHelper.getBoolean(
            SequenceStyleGenerator.CONFIG_PREFER_SEQUENCE_PER_ENTITY,
            params,
            false
        );

        final String defaultSequenceName = preferSequencePerEntity
                ? params.getProperty(JPA_ENTITY_NAME) + sequencePerEntitySuffix
                : SequenceStyleGenerator.DEF_SEQUENCE_NAME;

        sequenceCallSyntax = dialect.getSequenceNextValString(
            ConfigurationHelper.getString(
                SequenceStyleGenerator.SEQUENCE_PARAM,
                params,
                defaultSequenceName
            )
        );
    }

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object obj) {
        if (obj instanceof Identifiable) {
            Identifiable identifiable = (Identifiable) obj;
            Serializable id = identifiable.getId();

            if (id != null) {
                return id;
            }
        }

        long seqValue = ((Number)
                Session.class.cast(session)
                .createNativeQuery(sequenceCallSyntax)
                .uniqueResult()
        ).longValue();

        return sequencePrefix + String.format("%011d%s", 0 ,seqValue);
    }
}

And map it like this:

@Id
@GenericGenerator(
	name = "assigned-sequence",
	strategy = "com.vladmihalcea.book.hpjp.hibernate.identifier.StringSequenceIdentifier",
	parameters = {
		@org.hibernate.annotations.Parameter(
			name = "sequence_name", value = "hibernate_sequence"),
		@org.hibernate.annotations.Parameter(
			name = "sequence_prefix", value = "CTC_"),
	}
)
@GeneratedValue(
	generator = "assigned-sequence",
	strategy = GenerationType.SEQUENCE)
private String id;

Check out this article for more details.

Thanks but is it possible to do it with just xml instead of using annotations for mapping?

why is it asking me to implement unimplemented methods in class name

it implements the following sets of code
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
// TODO Auto-generated method stub
return null;
}
}

also it asks me to remove @Override from generate method

Yes, you can use XML too, but why would you use a deprecated mapping model?

It seems you are using an old Hibernate version. Upgrade to 5.2 and it will work. Or adapt it to the old method signature. It’s very easy. You’ll figure it out.

i’m using the latest version of hibernate and JPA

These are my gradle dependencies
implementation ‘org.springframework.boot:spring-boot-starter-web’
implementation ‘mysql:mysql-connector-java:8.0.15’
implementation ‘org.hibernate:hibernate-core:5.4.1.Final’
implementation ‘org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final’

i m confused.

Check out my StringSequenceIdentifierTest in my high-performance-java-persistence GitHub repository.

Just run the test and you’ll see that it works like a charm.

Is that custom string id possible with MySQL db?

MySQL does not support sequences, so you could not do that for the PK. Only if thevPK is identity and you use that value to build a secondary column with the String prefix amd the ID value combined.

Hi @vlad
I have a issue in generating custom sequence using SequenceStyleGenerator
Can you look into it

The issue is due to LongType is deprecated in hibarnate 6

1 Like

Better late than never!
Regarding the LongType issue, you can switch to:
super.configure(new TypeConfiguration().getBasicTypeRegistry().getRegisteredType(Long.class), params, serviceRegistry);

@vlad your post helped the community so much on SequenceStyleGenerator usage, I’m wondering if you have a plan to have another post for using SequenceStyleGenerator in Hibernate 6, as well as new supports for strong type. I believe it will be super helpful. (Sorry if this is unrelated)