Mastering Hibernate and JPA Annotations: Unveiling the Power of Entity Management
Welcome to the first part of our series on Hibernate and JPA Annotations. In this installment, we will delve into the essential concept of “Entity Management.” Understanding how to effectively manage entities is crucial in the world of Java Persistence API (JPA) and Hibernate. As we explore the intricacies of entity management, we will uncover the power of annotations in shaping the behavior of our entities. Whether you are a seasoned developer or a newcomer to Hibernate, this series aims to provide valuable insights into the world of Java-based persistence. Let’s embark on this journey to master the art of entity management with Hibernate and JPA Annotations.
I am going to explain the topic using a real project, so I create a Maven project using start.spring.io and download it.
I add the following settings to the application.properties
file. (I assume you have PostgreSQL installed on your PC, or feel free to use your favorite database.):
# PostgreSQL Configuration
spring.datasource.url=jdbc:postgresql://localhost:5432/<your postgresql db name here>
spring.datasource.username=<your postgresql user name here>
spring.datasource.password=<your postgresql password here>
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=update
And I create the Employee
class and add some annotations to it:
package com.azizkale.anotations_tutoraial.api;
import jakarta.persistence.*;
@Entity
@Table(name="employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column
private int id;
@Column
private String name;
}
Now, when you run the project, you will observe that Hibernate has created a table for the Employee
entity in your database. Not only does it stop there, but it has also added some features to the table.
Let’s discuss these features and the meanings of annotations:
@Entity
The @Entity
annotation indicates that a Java class is marked as a Java Persistence API (JPA) entity. JPA provides a standard for object-relational mapping (ORM) in Java applications, and this annotation specifies that a class will be mapped to a database table.
The @Entity
annotation provides the following basic elements:
- Table Naming: If the class name differs from the table name, the
name
attribute can be used to specify the table name. - Database Schema: If a database schema needs to be specified, it can be done using the
schema
attribute. - Catalog Name: If a catalog name needs to be specified, it can be done using the
catalog
attribute. - Indexing: Indexes can be created in the database using indexing properties.
@Table
The @Table
annotation is used to specify the database table associated with a JPA entity. This annotation allows you to configure which database table an entity class will be mapped to. It is not necessary to use this annotation when the table name matches the name of the associated entity class. However, it is useful when a different table name or a custom schema needs to be used, as mentioned in the first point of the explanation above.
@Id
The @Id annotation signifies that a field is the primary key within a JPA entity. The primary key uniquely identifies each record in a database table, representing a field that uniquely distinguishes one entry from another.
@GeneratedValue
This signifies that the values of primary key fields in JPA entity classes will be generated automatically. This is typically achieved using an automatically incremented sequence number provided by the database or another specified strategy. The annotation prevents the manual assignment of primary key values and commonly utilizes a mechanism controlled by the database for value generation.
GenerationType:
GenerationType enum is used to specify the automatic key generation strategies offered by JPA (Java Persistence API). These strategies determine how you generate primary key values for an entity. Here are some properties of the GenerationType enum:
- GenerationType.AUTO: The JPA implementation chooses a database-specific key generation strategy. Typically, it will first try SEQUENCE or IDENTITY strategies and if one of them is supported, it will use it.
- GenerationType.IDENTITY: The primary key value is automatically generated by the database. Usually, this is achieved by using the database’s auto-increment columns or a similar mechanism.
- GenerationType.SEQUENCE: Generate a primary key value using a database sequence. This strategy creates a database object and then generates primary keys using the nextval value of that object.
- GenerationType.TABLE: A primary key value is generated using a database table. This strategy keeps the key values in a custom table and updates this table every time a new value is needed.
@Column
The @Column
annotation specifies how a field is mapped to columns in a database table. If this annotation is not used, JPA uses the name of the field by default.
@Column(name = "employee_name")
private String name;
@Column(name = "employee_code", unique = true)
private String employeeCode;
@Column(name = "email", nullable = false)
private String email;
@Column(name = "adress", length = 1000)
private String adress;
@Column(name = "price", precision = 10, scale = 2)
private BigDecimal price;
@Column(name = "description", columnDefinition = "VARCHAR(255) DEFAULT 'Default Value'")
private String description;
Let’s take a look at the attributes of this annotation:
- name: Specifies the name of the column in the database.
- unique: The
unique
attribute of the@Column
annotation is a boolean value that indicates whether the column values should be unique across all rows in the table. - nullable: This property specifies whether a column is nullable (can take null values). Its default value is true.
- length: This property specifies the maximum length of a character column. This property is especially useful for columns of type VARCHAR.
- precision and scale: These properties specify the precision of numeric columns and the number of decimal places. precision specifies the total number of digits and scale specifies the number of decimal places.
- columnDefinition: This property provides an SQL statement that specifies the type of the column and other properties in the database.
@version
@Version
is an annotation provided by the Java Persistence API (JPA), and it is used to implement an optimistic locking strategy. Optimistic locking is a method used to control concurrent changes made to the same data.
The @Version
annotation is typically applied to a field in an entity class. This field holds the version number of the class representing the data. The version number increases with each update operation, allowing tracking of changes made concurrently. This helps in managing simultaneous modifications to the data.
@Entity
@Table(name="employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column
private int id;
@Column
private String name;
// another columns
@Version
@Column(name = "version")
private Long version;
}
In this example, @Version
annotation indicates that the version field is an optimistic locking version number. The value of this field is automatically incremented during each update operation.
Thanks to this version number, when a user reads data, they also get the version number. Later, when this user wants to make an update, he can check the version number to see if another user has updated the same data. If another user has updated the data and the version number has changed, the update is rejected or managed appropriately.
This strategy aims to minimize locking times in the database and is usually preferred when many users are working simultaneously on the system.
@OrderBy
The@OrderBy
annotation allows sorting on a relationship. In particular, it is used to sort the elements of a collection in a relationship according to a specific property.
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "author")
@OrderBy("publicationYear DESC")
private List<Book> books;
// getters and setters
}
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private int publicationYear;
@ManyToOne
@JoinColumn(name = "author_id")
private Author author;
// getters and setters
}
In this example, the books field in the Author class will be a list sorted in descending order by the publicationYear property in the Book class. The value of the@OrderBy
annotation expresses the sorting criterion.
@Transient
This annotation indicates that a field or method is not persistent in the database. In other words, it signifies that the field or method does not have a corresponding column in the database.
The @Transient
annotation is typically used in the following scenarios:
- Temporary Data: It is employed for temporary data that doesn’t need to be stored in the database. For instance, a temporary field derived from calculations.
- Fields That Shouldn’t Be Persisted: If there is a specific field that you don’t want to store in the database, you can mark it with
@Transient
.
In summary, @Transient
is used to specify that certain fields or methods should not be persisted in the database.
@Lob
The @Lob
(Large Object) annotation is provided by the Java Persistence API (JPA) and is applied to fields representing large data objects such as BLOBs (Binary Large Objects) or CLOBs (Character Large Objects). This annotation is used to store large data objects in the database.
The @Lob
annotation is typically used in the following scenarios:
- Large Text or Data Blobs: It can be applied to fields representing large data objects such as text documents or image files.
- For CLOB and BLOB Types: When you want to use CLOB (Character Large Object) or BLOB (Binary Large Object) types in the database.
Conclusion
In summary, our journey into Hibernate and JPA Annotations for Entity Management has revealed the powerful role these annotations play in shaping database interactions. From basic annotations like @Entity
and @Table
to advanced features such as @Version
for optimistic locking and @OrderBy
for sorting relationships, each annotation contributes to effective Java-based persistence. The use of @Transient
and @Lob
provides solutions for excluding fields and handling large data objects. Mastering these annotations is essential for crafting efficient and robust database solutions. Stay tuned for more insights in the upcoming parts of our Hibernate and JPA Annotations series.
Happy coding!