Hibernate JPA Sequence (non-Id)

Is it possible to use a DB sequence for some column that is not the identifier/is not part of a composite identifier?

I'm using hibernate as jpa provider, and I have a table that has some columns that are generated values (using a sequence), although they are not part of the identifier.

What I want is to use a sequence to create a new value for an entity, where the column for the sequence is NOT (part of) the primary key:

@Table(name = "MyTable")
public class MyEntity {

    @Id //... etc
    public Long getId() {
        return id;

   //note NO @Id here! but this doesn't work...
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "myGen")
    @SequenceGenerator(name = "myGen", sequenceName = "MY_SEQUENCE")
    @Column(name = "SEQ_VAL", unique = false, nullable = false, insertable = true, updatable = true)
    public Long getMySequencedValue(){
      return myVal;


Then when I do this:

em.persist(new MyEntity());

the id will be generated, but the mySequenceVal property will be also generated by my JPA provider.

Just to make things clear: I want Hibernate to generate the value for the mySequencedValue property. I know Hibernate can handle database-generated values, but I don't want to use a trigger or any other thing other than Hibernate itself to generate the value for my property. If Hibernate can generate values for primary keys, why can't it generate for a simple property?


Looking for answers to this problem, I stumbled upon this link

It seems that Hibernate/JPA isn't able to automatically create a value for your non-id-properties. The @GeneratedValue annotation is only used in conjunction with @Id to create auto-numbers.

The @GeneratedValue annotation just tells Hibernate that the database is generating this value itself.

The solution (or work-around) suggested in that forum is to create a separate entity with a generated Id, something like this:

public class GeneralSequenceNumber {
  private Long number;

public class MyEntity {
  @Id ..
  private Long id;

  private GeneralSequnceNumber myVal;

I found that @Column(columnDefinition="serial") works perfect but only for PostgreSQL. For me this was perfect solution, because second entity is "ugly" option.

I know this is a very old question, but it's showed firstly upon the results and jpa has changed a lot since the question.

The right way to do it now is with the @Generated annotation. You can define the sequence, set the default in the column to that sequence and then map the column as:

@Column(name = "column_name", insertable = false)

Hibernate definitely supports this. From the docs:

"Generated properties are properties which have their values generated by the database. Typically, Hibernate applications needed to refresh objects which contain any properties for which the database was generating values. Marking properties as generated, however, lets the application delegate this responsibility to Hibernate. Essentially, whenever Hibernate issues an SQL INSERT or UPDATE for an entity which has defined generated properties, it immediately issues a select afterwards to retrieve the generated values."

For properties generated on insert only, your property mapping (.hbm.xml) would look like:

<property name="foo" generated="insert"/>

For properties generated on insert and update your property mapping (.hbm.xml) would look like:

<property name="foo" generated="always"/>

Unfortunately, I don't know JPA, so I don't know if this feature is exposed via JPA (I suspect possibly not)

Alternatively, you should be able to exclude the property from inserts and updates, and then "manually" call session.refresh( obj ); after you have inserted/updated it to load the generated value from the database.

This is how you would exclude the property from being used in insert and update statements:

<property name="foo" update="false" insert="false"/>

Again, I don't know if JPA exposes these Hibernate features, but Hibernate does support them.

As a followup here's how I got it to work:

@Override public Long getNextExternalId() {
    BigDecimal seq =
        (BigDecimal)((List)em.createNativeQuery("select col_msd_external_id_seq.nextval from dual").getResultList()).get(0);
    return seq.longValue();

Although this is an old thread I want to share my solution and hopefully get some feedback on this. Be warned that I only tested this solution with my local database in some JUnit testcase. So this is not a productive feature so far.

I solved that issue for my by introducing a custom annotation called Sequence with no property. It's just a marker for fields that should be assigned a value from an incremented sequence.

public @interface Sequence

Using this annotation i marked my entities.

public class Area extends BaseEntity implements ClientAware, IssuerAware
    @Column(name = "areaNumber", updatable = false)
    private Integer areaNumber;

To keep things database independent I introduced an entity called SequenceNumber which holds the sequence current value and the increment size. I chose the className as unique key so each entity class wil get its own sequence.

@Table(name = "SequenceNumber", uniqueConstraints = { @UniqueConstraint(columnNames = { "className" }) })
public class SequenceNumber
    @Column(name = "className", updatable = false)
    private String className;

    @Column(name = "nextValue")
    private Integer nextValue = 1;

    @Column(name = "incrementValue")
    private Integer incrementValue = 10;

    ... some getters and setters ....

The last step and the most difficult is a PreInsertListener that handles the sequence number assignment. Note that I used spring as bean container.

public class SequenceListener implements PreInsertEventListener
    private static final long serialVersionUID = 7946581162328559098L;
    private final static Logger log = Logger.getLogger(SequenceListener.class);

    private SessionFactoryImplementor sessionFactoryImpl;

    private final Map<String, CacheEntry> cache = new HashMap<>();

    public void selfRegister()
        // As you might expect, an EventListenerRegistry is the place with which event listeners are registered
        // It is a service so we look it up using the service registry
        final EventListenerRegistry eventListenerRegistry = sessionFactoryImpl.getServiceRegistry().getService(EventListenerRegistry.class);

        // add the listener to the end of the listener chain
        eventListenerRegistry.appendListeners(EventType.PRE_INSERT, this);

    public boolean onPreInsert(PreInsertEvent p_event)
        updateSequenceValue(p_event.getEntity(), p_event.getState(), p_event.getPersister().getPropertyNames());

        return false;

    private void updateSequenceValue(Object p_entity, Object[] p_state, String[] p_propertyNames)
            List<Field> fields = ReflectUtil.getFields(p_entity.getClass(), null, Sequence.class);

            if (!fields.isEmpty())
                if (log.isDebugEnabled())
                    log.debug("Intercepted custom sequence entity.");

                for (Field field : fields)
                    Integer value = getSequenceNumber(p_entity.getClass().getName());

                    field.set(p_entity, value);
                    setPropertyState(p_state, p_propertyNames, field.getName(), value);

                    if (log.isDebugEnabled())
                        LogMF.debug(log, "Set {0} property to {1}.", new Object[] { field, value });
        catch (Exception e)
            log.error("Failed to set sequence property.", e);

    private Integer getSequenceNumber(String p_className)
        synchronized (cache)
            CacheEntry current = cache.get(p_className);

            // not in cache yet => load from database
            if ((current == null) || current.isEmpty())
                boolean insert = false;
                StatelessSession session = sessionFactoryImpl.openStatelessSession();

                SequenceNumber sequenceNumber = (SequenceNumber) session.get(SequenceNumber.class, p_className);

                // not in database yet => create new sequence
                if (sequenceNumber == null)
                    sequenceNumber = new SequenceNumber();
                    insert = true;

                current = new CacheEntry(sequenceNumber.getNextValue() + sequenceNumber.getIncrementValue(), sequenceNumber.getNextValue());
                cache.put(p_className, current);
                sequenceNumber.setNextValue(sequenceNumber.getNextValue() + sequenceNumber.getIncrementValue());

                if (insert)

            return current.next();

    private void setPropertyState(Object[] propertyStates, String[] propertyNames, String propertyName, Object propertyState)
        for (int i = 0; i < propertyNames.length; i++)
            if (propertyName.equals(propertyNames[i]))
                propertyStates[i] = propertyState;

    private static class CacheEntry
        private int current;
        private final int limit;

        public CacheEntry(final int p_limit, final int p_current)
            current = p_current;
            limit = p_limit;

        public Integer next()
            return current++;

        public boolean isEmpty()
            return current >= limit;

As you can see from the above code the listener used one SequenceNumber instance per entity class and reserves a couple of sequence numbers defined by the incrementValue of the SequenceNumber entity. If it runs out of sequence numbers it loads the SequenceNumber entity for the target class and reserves incrementValue values for the next calls. This way I do not need to query the database each time a sequence value is needed. Note the StatelessSession that is being opened for reserving the next set of sequence numbers. You cannot use the same session the target entity is currently persisted since this would lead to a ConcurrentModificationException in the EntityPersister.

Hope this helps someone.

I run in the same situation like you and I also didn't find any serious answers if it is basically possible to generate non-id propertys with JPA or not.

My solution is to call the sequence with a native JPA query to set the property by hand before persisiting it.

This is not satisfying but it works as a workaround for the moment.


I fixed the generation of UUID (or sequences) with Hibernate using @PrePersist annotation:

public void initializeUUID() {
    if (uuid == null) {
        uuid = UUID.randomUUID().toString();

I've found this specific note in session 9.1.9 GeneratedValue Annotation from JPA specification: "[43] Portable applications should not use the GeneratedValue annotation on other persistent fields or properties." So, I presume that it is not possible to auto generate value for non primary key values at least using simply JPA.

"I don't want to use a trigger or any other thing other than Hibernate itself to generate the value for my property"

In that case, how about creating an implementation of UserType which generates the required value, and configuring the metadata to use that UserType for persistence of the mySequenceVal property?

This is not the same as using a sequence. When using a sequence, you are not inserting or updating anything. You are simply retrieving the next sequence value. It looks like hibernate does not support it.

If you are using postgresql And i'm using in spring boot 1.5.6

@Column(columnDefinition = "serial")
private Integer orderID;

I've been in a situation like you (JPA/Hibernate sequence for non @Id field) and I ended up creating a trigger in my db schema that add a unique sequence number on insert. I just never got it to work with JPA/Hibernate

After spending hours, this neatly helped me to solve my problem:

For Oracle 12c:


For H2:

ID BIGINT GENERATED as auto_increment

Also make:

@Column(insertable = false)

Need Your Help

How to use HTTPS on Node.js using Express/Socket.io

node.js express https socket.io

Im trying to run my node server with https. I'm using express and socket.io.

How to configure where to redirect after a log out in Django?

django authentication

Just wondering where I can set the url to redirect to after logout. I know you can set the login url. I want to redirect to my home page.