Is it a good idea to use universally unique identifier (UUID) as a database key? Or is it better to use auto increment Long value?
We can easily create random UUID by using this method in Java:UUID uuid = UUID.randomUUID();
UUID example: 41b62562-2362-11ea-978f-2e728ce88125.
UUID type is longer than Long type. UUID type has 16 bytes, Long type has 8 bytes. Using classic auto increment Long consumes less resources than UUID. However, UUID has many advantages:
- Easy to scale. We do not need a central unit to generate UUIDs. We can combine or split components even from different environments without worry about duplication.
- UUID can be generated in Java and we do not have to wait for the result from the database.
- It is more secure, attackers cannot simply increment keys to get secret data. Of course we have to check right always, but this can save us in case of a developer mistake.
Tips:
- Always store UUID in the database as UUID type, not as Varchar type.
- It is a good idea to store also auto increment Long as well. It is useful when we want to implement pagination. It is important to have a clear sequential order defined. Otherwise, we are at risk of duplicate paging values.
Do not use UUID type in Java directly. This is a better approach:
public class TaskId { private final UUID id; private TaskId(UUID id) { this.id = id; } public UUID getId() { return id; } public static TaskId fromUUID(UUID uuid) { if(uuid == null) { return null; } return new TaskId(uuid); } public static TaskId fromString(String val) { if(val == null) { return null; } return new TaskId(UUID.fromString(val)); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TaskId that = (TaskId) o; return Objects.equals(id, that.id); } @Override public int hashCode() { return Objects.hash(id); } @Override public String toString() { return id.toString(); } }
It looks like a lot of boilerplate code. But you really appreciate it in the case of a large project, where it is clear what type of value it is. Calling this method:
public void storeTask(DocumentId documentId, TaskId taskId) {...}
is more clear and type safe than
public void storeTask(UUID documentId, UUID taskId) {...}