Entity ID in Spring Boot is a unique identifier assigned to an entity in a database table. It serves to distinguish one entity from another and is often used as the primary key for the table.
Entity IDs are essential for establishing relationships between entities and enforcing referential integrity. Spring Boot's data access framework, Spring Data JPA, provides built-in support for managing entity IDs and simplifying the process of creating, reading, updating, and deleting data from a database.
Types of identifiers
When it comes to identifiers, there are generally two types: numerical and string-based. Numerical identifiers are typically integers that increment with each new record added to a database, while string-based identifiers use alphanumeric characters to create unique identifiers.
Numeric identifiers are easy to manage, sort and search, but they are not ideal for certain types of applications, such as those where privacy and security are a concern. This is because it's relatively easy to guess or hack a numerical identifier, which can lead to unauthorized access to sensitive information.
On the other hand, string-based identifiers, as the name suggests, are identifiers that use string values to uniquely identify an entity. Unlike numerical IDs, string-based IDs are not generated sequentially or automatically. Instead, they can be any combination of characters, such as letters, numbers, and symbols.
One commonly used type of string-based identifier is the Universally Unique Identifier (UUID). A UUID is a 128-bit string that is guaranteed to be unique, even across multiple systems and databases.
UUIDs are commonly used in distributed systems where data is stored on multiple servers or devices. They are also useful for applications where privacy and security are a concern, such as in healthcare or financial services.
In Spring Boot, there are different types of identifiers that can be used as entity keys, including numerical and string-based identifiers, such as UUIDs.
To define an entity key in Spring Boot, we can use the @Id annotation on the field that will be used as the primary key for the entity. Also the @GeneratedValue annotation is commonly used to specify how the value for the entity key will be generated.
Numeric identifiers are typically integers that increment with each new record added to a database. We can use the @GeneratedValue(strategy = GenerationType.IDENTITY) annotation to generate a numeric identifier for the primary key. This strategy relies on the database's identity column feature to generate unique IDs for each record.
Here's an example of how we can use the @Id and @GeneratedValue annotations in Spring Boot:
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
// other fields and methods
// constructor, getters and setters
}In case of using string-based identifiers we can write the @GeneratedValue(strategy = GenerationType.UUID) annotation to generate a UUID for the primary key. This strategy generates a unique identifier for each record using the UUID algorithm:
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
// other fields and methods
// constructor, getters and setters
}With this configuration, each time we create a new Product entity, a new UUID will be generated and assigned to the id field. This ensures that the id value is unique and doesn't clash with any other Product entities in the database.
Generation strategies
In Spring Boot, there are several generation strategies that can be used with the @GeneratedValue annotation to automatically create IDs for entities. Here are some of the most common strategies along with their pros and cons:
AUTO
The AUTO strategy is the default strategy and allows the persistence provider to choose the appropriate strategy based on the underlying database. For example, it might use an identity column for MySQL, a sequence for Oracle, and a table for H2. This strategy is generally the easiest to use because it doesn't require any additional configuration, but it can also be less efficient because it may require additional queries to obtain the generated ID.
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// other fields and methods
// constructor, getters and setters
}TABLE
The TABLE strategy generates IDs using a database table to store the current value of the ID. This strategy can be useful in distributed systems where multiple instances of the application need to generate unique IDs.
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "customer_generator")
@TableGenerator(name = "customer_generator", table = "id_generator", pkColumnName = "sequence_name",
valueColumnName = "next_val", allocationSize = 1)
private Long id;
private String firstName;
private String lastName;
// constructor, getters and setters
}In this example, we also define a generator named "customer_generator" and associate it with a database table named "id_generator" using the @TableGenerator annotation.
The "id_generator" table should have at least two columns: "sequence_name" and "next_val". The "sequence_name" column stores a unique name for each ID sequence, while the "next_val" column stores the next available value for each sequence. When an ID is needed for a new entity, Spring Boot will query the "id_generator" table, increment the "next_val" value for the specified sequence, and use the result as the entity's ID.
Note that the specifics of the "id_generator" table may vary depending on the database and configuration. Also, the TABLE strategy can be less efficient than other strategies because it requires additional queries to obtain the next ID value.
IDENTITY
The IDENTITY strategy generates numeric IDs using an identity column in the database. This strategy can be very efficient because it doesn't require additional queries to obtain the generated ID. However, it may not be suitable for all databases, and it can also lead to issues with replication or clustering.
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// other fields and methods
// constructor, getters and setters
}SEQUENCE
The SEQUENCE strategy generates numeric IDs using a database sequence. This strategy can be very efficient and is often the preferred strategy for large-scale applications because it minimizes the risk of ID collisions.
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_seq")
@SequenceGenerator(name = "product_seq", sequenceName = "product_sequence", allocationSize = 1)
private Long id;
private String name;
private Double price;
// constructor, getters and setters
}In this example, we also define a sequence generator named "product_seq" and associate it with the database sequence named "product_sequence" using the @SequenceGenerator annotation.
When an ID is needed for a new entity, Spring Boot will increment the sequence value by the specified allocationSize and use the result as the entity's ID. The allocationSize property specifies how many IDs should be cached in memory before making another query to the database.
Note that not all databases support sequences, so the availability of this strategy may vary depending on the database used. Also, the sequence value may not always be contiguous, since it can be incremented by other processes accessing the same sequence.
To sum up, the choice of generation strategy depends on the specific requirements of the application. The AUTO strategy is often the easiest to use, but it may not be the most efficient. The TABLE strategy is useful in distributed systems, while the IDENTITY and SEQUENCE strategies are preferred for their efficiency and reliability.
Note that Spring Boot allows you not to set generation parameters in types such as TABLE and SEQUENCE. In this case, all the necessary tables and sequences will be created automatically.
Custom generator
In addition to the built-in ID generation strategies provided by Spring Boot, it is also possible to create custom ID generators to meet specific application requirements. A custom ID generator can be created by implementing the org.hibernate.id.IdentifierGenerator interface.
Here's an example of creating a custom ID generator for generating unique IDs based on the current timestamp:
package com.example;
public class TimestampIdGenerator implements IdentifierGenerator {
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
return Instant.now().toEpochMilli();
}
}In this example, we define a custom ID generator named TimestampIdGenerator in the com.example package by implementing the IdentifierGenerator interface. The generate method is responsible for generating a unique ID for each entity. In this case, we generate a unique ID based on the current timestamp in milliseconds using the Instant.now() method.
To use this custom ID generator with an entity in Spring Boot, we annotate the ID field with @GeneratedValue and specify the custom generator class using the generator attribute, like this:
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(generator = "timestamp-id")
@GenericGenerator(name = "timestamp-id", strategy = "com.example.TimestampIdGenerator")
private Long id;
// other fields and methods
}In this example, we annotate the id field with @GeneratedValue and specify the custom generator class com.example.TimestampIdGenerator using the @GenericGenerator annotation. When an ID is needed for a new Order entity, Spring Boot will call the generate method of the custom generator to generate a unique timestamp-based ID for the entity.
What does a proper ID look like?
Both numerical and string-based identifiers have their advantages and disadvantages, and the choice of which type to use will depend on the specific needs of the application.
String-based IDs have a few advantages over numerical IDs. One of the main advantages is that they are more complex and difficult to guess, making them ideal for situations where privacy and security are a concern.
However, there are also some potential drawbacks to using string-based IDs. For example, they can be longer and take up more space than numerical IDs, which can impact database performance. They can also be more difficult to search and sort, since they are not easily sortable in numerical order.
The format of a proper ID depends on the type of identifier used. For numeric identifiers, a proper ID should be a non-negative integer value that uniquely identifies the entity within the database table.
For string-based identifiers such as UUIDs, a proper ID should be a string value that conforms to the UUID format. The UUID format is a standardized way of representing a universally unique identifier, which consists of 32 hexadecimal digits separated by hyphens.
For example, a proper UUID looks like this:
123e4567-e89b-12d3-a456-426655440000In general, it is recommended to make entity IDs immutable in order to ensure consistency and avoid unintended changes. This is because the entity ID is often used as a reference to uniquely identify an entity within a system, and changing the ID could potentially cause confusion or errors.
It's also important to note that the uniqueness of the ID is a critical requirement to avoid conflicts between entities. So, the ID should be carefully chosen or generated to ensure uniqueness. Additionally, the chosen ID should be easily convertible and stored in the chosen data store.
Conclusion
The entity ID is a crucial part of an entity in Spring Boot, as it provides a unique identifier that can be used to identify and access the entity. The ID can be generated automatically by Spring Boot using built-in strategies such as AUTO, TABLE, IDENTITY, SEQUENCE, or UUID, or it can be defined using a custom generator to meet specific application requirements.
When defining the ID for an entity, it is important to choose a suitable data type, such as numbers or strings, and to ensure that the ID is unique and immutable. You can also use composite identifiers to define unique identifiers for entities that require multiple columns or properties to uniquely identify them.
Overall, the entity ID is a fundamental aspect of Spring Boot applications, and choosing the right ID generation strategy and data type is essential for ensuring the performance and scalability of the application.