Sunday, October 2, 2022
HomeJavagenerate UUIDs as major keys with Hibernate

generate UUIDs as major keys with Hibernate


Most builders favor numerical major keys as a result of they’re environment friendly to make use of and simple to generate. However that doesn’t imply {that a} major key needs to be a quantity.

UUIDs, for instance, have gained some recognition over current years. The principle benefit of a UUID is its (sensible) international uniqueness which offers an enormous benefit for distributed methods.

In case you use the everyday numerical ID that will get incremented for every new file, you should generate all IDs by the identical system element. Usually, this can be a sequence for every desk that’s managed by your database. This makes that sequence the one supply of failure. Different approaches, e.g., a clustered database or every other horizontally scaled quantity generator, require communication between the nodes. That clearly creates some effort that slows down the technology of your major key values.

You don’t want any of this when utilizing a globally distinctive UUID. Every element can generate its personal UUIDs, and there won’t be any conflicts. That’s why UUIDs have grow to be widespread in microservice-based architectures or when creating offline purchasers.

Then again, the UUID additionally has some disadvantages. The obvious one is its dimension. It’s 4 occasions bigger than a numerical ID and may’t be dealt with as effectively. You must, due to this fact, resolve rigorously if you wish to use UUIDs or numeric IDs and focus on it together with your database administrator.

In case you resolve to make use of UUIDs, you’ll be able to, after all, additionally persist them with Hibernate. When doing that, you should resolve the way you wish to generate the UUID worth. You’ll be able to, after all, generate it your self and set it in your entity object earlier than persisting it. Or, should you’re utilizing Hibernate 4, 5, or 6 or JPA 3.1, you’ll be able to outline a technology technique in your entity mappings. I’ll present you the way to try this on this article.

Producing UUIDs utilizing JPA 3.1

Since JPA 3.1, you’ll be able to annotate a major key attribute with @GeneratedValue and set the technique to GenerationType.UUID. Primarily based on the specification, your persistence supplier shall generate a UUID worth primarily based on IETF RFC 4122.

@Entity
public class E-book {

	@Id
	@GeneratedValue(technique = GenerationType.UUID)
	personal UUID id;
	
	…
}

Let’s do this mapping and persist a brand new E-book entity object.

E-book b = new E-book();
b.setTitle("The Hound of the Baskervilles");
b.setPublishingDate(LocalDate.of(1902, 4, 30));
em.persist(b);

You’ll be able to see within the log output that Hibernate generated a UUID worth and set it on the E-book entity object earlier than it continued it within the database.

18:27:50,009 DEBUG AbstractSaveEventListener:127 - Generated identifier: 21e22474-d31f-4119-8478-d9d448727cfe, utilizing technique: org.hibernate.id.UUIDGenerator
18:27:50,035 DEBUG SQL:128 - insert into E-book (publishingDate, title, model, id) values (?, ?, ?, ?)
18:27:50,039 TRACE bind:28 - binding parameter [1] as [DATE] - [1902-04-30]
18:27:50,040 TRACE bind:28 - binding parameter [2] as [VARCHAR] - [The Hound of the Baskervilles]
18:27:50,040 TRACE bind:28 - binding parameter [3] as [INTEGER] - [0]
18:27:50,040 TRACE bind:28 - binding parameter [4] as [BINARY] - [21e22474-d31f-4119-8478-d9d448727cfe]

Limitations and portability points

IETF RFC 4122 defines 4 totally different methods to generate UUIDs. However sadly, JPA 3.1 doesn’t specify which model your persistence supplier shall use. It additionally doesn’t outline any moveable mechanism to customise this technology course of.

As a consequence of that, your persistence supplier can resolve the way it generates UUID values. And this conduct would possibly differ between JPA implementations.

While you use Hibernate as your persistence supplier, it generates the UUID worth primarily based on random numbers, as outlined by IETF RFC 4122 Model 4. I get into extra particulars about that after I present you Hibernate’s proprietary UUID turbines.

Producing UUIDs utilizing Hibernate 4, 5 and 6

As talked about earlier, IETF RFC 4122 defines 4 totally different methods to generate UUIDs. Hibernate helps 2 of them:

  1. The default technique generates the UUID primarily based on random numbers (IETF RFC 4122 Model 4).
  2. You may also configure a generator that makes use of the IP handle of the machine and a timestamp (IETF RFC 4122 Model 1).

The definition of the technique you wish to use depends upon your Hibernate model. Let’s take a look on the default technique first.

Random quantity primarily based UUID (IETF RFC 4122 model 4)

By default, Hibernate makes use of a random quantity primarily based technology technique. That is additionally the technique that Hibernate makes use of should you use the beforehand described, JPA-based definition.

Random quantity primarily based UUID in Hibernate 6

Utilizing Hibernate 6, you’ll be able to annotate your major key attribute with @UuidGenerator and set the fashion to RANDOM, AUTO, or don’t specify it. In all 3 instances, Hibernate will apply its default technique.

@Entity
public class E-book {
	
	@Id
	@GeneratedValue
    @UuidGenerator
	personal UUID id;

	...
}

Let’s use this mapping with the take a look at as I confirmed you earlier than.

E-book b = new E-book();
b.setTitle("The Hound of the Baskervilles");
b.setPublishingDate(LocalDate.of(1902, 4, 30));
em.persist(b);

Unsurprisingly, this will get you a similar log output as within the earlier take a look at case. Internally, Hibernate used the identical fashion after I used JPA’s mapping annotations.

18:28:25,859 DEBUG AbstractSaveEventListener:127 - Generated identifier: ac864ed4-bd3d-4ca0-8ba2-b49ec74465ff, utilizing technique: org.hibernate.id.uuid.UuidGenerator
18:28:25,879 DEBUG SQL:128 - insert into E-book (publishingDate, title, model, id) values (?, ?, ?, ?)
18:28:25,886 TRACE bind:28 - binding parameter [1] as [DATE] - [1902-04-30]
18:28:25,887 TRACE bind:28 - binding parameter [2] as [VARCHAR] - [The Hound of the Baskervilles]
18:28:25,887 TRACE bind:28 - binding parameter [3] as [INTEGER] - [0]
18:28:25,888 TRACE bind:28 - binding parameter [4] as [BINARY] - [ac864ed4-bd3d-4ca0-8ba2-b49ec74465ff]

Random quantity primarily based UUID in Hibernate 4 and 5

In case you’re utilizing Hibernate 4 or 5, you need to use the identical characteristic. However you should put a little bit further effort into your mapping definition.

You should annotate your major key attribute with a @GeneratedValue annotation. In that annotation, you should reference a customized generator and outline that generator utilizing Hibernate’s @GenericGenerator annotation. The @GenericGenerator annotation requires 2 parameters, the identify of the generator and the identify of the category that implements the generator. On this case, I known as the generator “UUID” and Hibernate shall use the category org.hibernate.id.UUIDGenerator.

@Entity
public class E-book {

	@Id
	@GeneratedValue(generator = "UUID")
	@GenericGenerator(
		identify = "UUID",
		technique = "org.hibernate.id.UUIDGenerator",
	)
	personal UUID id;
	
	…
}

That’s all you should do to inform Hibernate to generate a UUID as a major key. Let’s use this mapping to persist a brand new E-book entity object.

E-book b = new E-book();
b.setTitle("The Hound of the Baskervilles");
b.setPublishingDate(LocalDate.of(1902, 4, 30));
em.persist(b);

As you’ll be able to see within the log output, Hibernate generates a UUID and units it because the id worth earlier than it writes the brand new file to the database.

12:23:19,356 DEBUG AbstractSaveEventListener:118 – Generated identifier: d7cd23b8-991c-470f-ac63-d8fb106f391e, utilizing technique: org.hibernate.id.UUIDGenerator
12:23:19,388 DEBUG SQL:92 – insert into E-book (publishingDate, title, model, id) values (?, ?, ?, ?)
12:23:19,392 TRACE BasicBinder:65 – binding parameter [1] as [DATE] – [1902-04-30]
12:23:19,393 TRACE BasicBinder:65 – binding parameter [2] as [VARCHAR] – [The Hound of the Baskervilles]
12:23:19,393 TRACE BasicBinder:65 – binding parameter [3] as [INTEGER] – [0]
12:23:19,394 TRACE BasicBinder:65 – binding parameter [4] as [OTHER] – [d7cd23b8-991c-470f-ac63-d8fb106f391e]

IP and timestamp primarily based UUID (IETF RFC 4122 model 1)

Hibernate can even generate a UUID primarily based on IETF RFC 4122 model 1. Following the specification, it is best to generate the UUID with the MAC handle as a substitute of the IP handle. So long as no person is messing round with it, the MAC handle of every machine ought to be distinctive, and resulting from this assist to create a singular UUID.

Hibernate makes use of the IP handle as a substitute of the MAC handle. Basically, this isn’t a difficulty. But when the servers of your distributed system are operating on totally different networks, it is best to guarantee that none of them share the identical IP handle.

The configuration of the IETF RFC 4122 model 1 primarily based UUID generator is similar to the earlier one.

IP and timestamp primarily based UUID in Hibernate 6

The @UuidGenerator annotation launched in Hibernate 6 has a fashion attribute that you need to use to outline how Hibernate shall generate the UUID worth. While you set it to TIME, it makes use of a timestamp and the IP handle to generate the UUID worth.

@Entity
public class E-book {
	
	@Id
	@GeneratedValue
    @UuidGenerator(fashion = Type.TIME)
	personal UUID id;

	...
}

As you’ll be able to see within the code snippet, the one distinction from the earlier part is the worth of the technique attribute. Every little thing else continues to be the identical.

Let’s use this mapping to persist a brand new E-book entity object.

E-book b = new E-book();
b.setTitle("The Hound of the Baskervilles");
b.setPublishingDate(LocalDate.of(1902, 4, 30));
em.persist(b);

As you’ll be able to see, the log output appears to be like just like the earlier take a look at executions. Hibernate generates a brand new UUID worth and makes use of it to set the id attribute, earlier than it persists a brand new file within the E-book desk.

18:28:57,068 DEBUG AbstractSaveEventListener:127 - Generated identifier: c0a8b235-8207-1771-8182-07d7756a0000, utilizing technique: org.hibernate.id.uuid.UuidGenerator
18:28:57,095 DEBUG SQL:128 - insert into E-book (publishingDate, title, model, id) values (?, ?, ?, ?)
18:28:57,101 TRACE bind:28 - binding parameter [1] as [DATE] - [1902-04-30]
18:28:57,101 TRACE bind:28 - binding parameter [2] as [VARCHAR] - [The Hound of the Baskervilles]
18:28:57,102 TRACE bind:28 - binding parameter [3] as [INTEGER] - [0]
18:28:57,102 TRACE bind:28 - binding parameter [4] as [BINARY] - [c0a8b235-8207-1771-8182-07d7756a0000]

IP and timestamp primarily based UUID in Hibernate 4 and 5

In case you’re utilizing Hibernate 4 or 5, you should set a further parameter on the @GenericGenerator annotation to outline the technology technique. You’ll be able to see an instance of it within the following code snippet.

You outline the technique by offering a @Parameter annotation with the identify uuid_gen_strategy_class and the absolutely certified class identify of the technology technique as the worth.

@Entity
public class E-book {

	@Id
	@GeneratedValue(generator = "UUID")
	@GenericGenerator(
		identify = "UUID",
		technique = "org.hibernate.id.UUIDGenerator",
		parameters = {
			@Parameter(
				identify = "uuid_gen_strategy_class",
				worth = "org.hibernate.id.uuid.CustomVersionOneStrategy"
			)
		}
	)
	@Column(identify = "id", updatable = false, nullable = false)
	personal UUID id;
	
	…
}

While you now persist the brand new E-book entity, Hibernate will use the CustomVersionOneStrategy class to generate the UUID primarily based on IETF RFC 4122 model 1.

E-book b = new E-book();
b.setTitle("The Hound of the Baskervilles");
b.setPublishingDate(LocalDate.of(1902, 4, 30));
em.persist(b);

As you’ll be able to see within the log output, Hibernate makes use of each methods in the identical method.

12:35:22,760 DEBUG AbstractSaveEventListener:118 – Generated identifier: c0a8b214-578f-131a-8157-8f431d060000, utilizing technique: org.hibernate.id.UUIDGenerator
12:35:22,792 DEBUG SQL:92 – insert into E-book (publishingDate, title, model, id) values (?, ?, ?, ?)
12:35:22,795 TRACE BasicBinder:65 – binding parameter [1] as [DATE] – [1902-04-30]
12:35:22,795 TRACE BasicBinder:65 – binding parameter [2] as [VARCHAR] – [The Hound of the Baskervilles]
12:35:22,796 TRACE BasicBinder:65 – binding parameter [3] as [INTEGER] – [0]
12:35:22,797 TRACE BasicBinder:65 – binding parameter [4] as [OTHER] – [c0a8b214-578f-131a-8157-8f431d060000]

Abstract

As you’ve seen, you need to use UUIDs as major keys, and JPA and Hibernate outline alternative ways to generate UUID values.

JPA 3.1 provides the worth UUID to the GenerationType enum and requires the persistence supplier to generate a UUID primarily based on IETF RFC 4122. Nevertheless it doesn’t outline which of the 4 approaches shall be used and doesn’t present any moveable option to customise the UUID technology.

Hibernate can generate UUID values for a number of years now. In variations 4 and 5, you should use a @GenericGenerator and supply the category of the generator you wish to use. Hibernate 6 simplified this by introducing the @UuidGenerator annotation for it.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments