Skip to main content

ID generation strategies

When we choose an ID for our entities we have to decide between natural keys and surrogate keys. In case of surrogate keys we have to define the way this key is generated and the choices are quite a few. We can use a UUID, or a @GeneratedValue. The @GeneratedValue should define either a strategy (IDENTITY, SEQUENCE, TABLE) or a generator. A generator is a custom implementation that we create in our code and assign the ID to our entity before persisting in the database. The 3 strategies are not all supported by all RDBMSs. Also, they are not all as performant. The TABLE should be in general be avoided unless we want special portability features. IDENTITY should also be avoided because of the severe performance penalties but we use it if our database is not supporting it and the one that we favour is the SEQUENCE one. More details are given bellow:

IDENTITY - auto generation

Th ID is generated outside of the transaction, at database level. This means that in case of a rollback discards an already generated id leading to identity gaps. Another problem is the performance because we need a database hit in order to get the identity of the entity and use it in our code in case we need it. This restriction is interfering with the writhe-behind technique that Hibernate adopts. According to this technique, batch processing is utilised and no change is propagated to the database until a change is affecting the result of a query. When we need the ID to be generated, the batch processing is disabled by hibernate resulting in huge performance impact. Finally, we cannot use it with inheritance type Table-per-concrete-class. On the other hand, the generation of the id by the database is considerably more light weight than generating it on Java code.

SEQUENCE


With this selection hibernate creates a sequence generator in the database and multiple tables and columns can use it. The advantage over IDENTITY is that it does not cause any issues with batch processing or inheritance. It can also preallocate values for improved performance.

TABLE (SEQUENCE)

This generation strategy creates a separate table that holds the next generated ID for each table. This table is read and updated accordingly on every insert. This strategy requires caution when it comes to concurrent generation requests. Performance here is traded in favour of database portability.

Comments

Popular posts from this blog

Notes on Lazy Loading

Hibernate is offering a configuration called LazyCollectionOption.EXTRA. Extra lazy collections means we can apply trivial operations to them without having to retrieve them from the database and without having to write these trivial queries to avoid doing so. Trivial operations are considered the size(), isEmpty() and contains(). If for example we have an entity User and an extra lazy collection called Address we can call user.getAddress.size() and this will generate a COUNT query on the ADDRESS table. So, no need to write a special query or load in memory the collection. Lazy loading is set by default to @OneToMany relations but you need to set it on @ManyToOne which are by default Eagerly loaded. @OneToOne can be lazy loaded only if the relation is not optional. If the relation is optional the the proxy will have to query the database to find out if it should be null or if it should be initiated. A spring boot property that needs to be overriden in all our applica...

Dirty checking

Every time we read a value from the database, a copy is stored in memory which is later used for dirty checking the entity. If we read too many values from the database without needing all of them, then we may run into OutOfMemoryException. This is why a good practice is to mark our session as read only if we plan on reading entities not for modifying them. This will tell Hibernate that once we are done, there is no reason for dirty checking as a result no copy of the entity needs to be done in the persistence context cache. We need to be very careful with collections and dirty checking. Always use property annotation on collection mappings. Otherwise, the dirty checking may consider the collection as modified and the result will be that all associated entities will be deleted and re-inserted.