Spring Data JPA simplifies database interactions in Java applications, by managing the complexity of object-relational mapping (ORM). At the hearth of this feature are annotation mapping Java objects to DB tables. In this reference, I explain how to use annotations such as @Entity
, @Table
, @Column
, @Id
, @ManyToOne
, and more, using a practical example.
Entity: Task Class
Let’s walk through the key annotations using a practical example of a Task in a task management system. Here, the Task
class is mapped to the tasks
table.
@Entity
@Table(name = "tasks")
public class Task {
// Fields and methods
}
By adding @Entity
to the Task
class, Spring Data JPA knows it should treat this class as a table in the database.
While @Entity
tells Spring Data JPA that this class represents a table, @Table
allows you to customize the table’s name and other settings. If @Table
is omitted, the table name defaults to the entity class name.
Defining Primary Keys
In this example, the id field is a primary key, automatically generated and incremented by the database.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
Every JPA entity requires a primary key to uniquely identify each row in the table. The @Id
annotation is used to mark the primary key field.
The @GeneratedValue
annotation defines how the primary key is generated. Common strategies include:
GenerationType.IDENTITY
: Relies on the database’s auto-increment feature.GenerationType.SEQUENCE
: Uses a database sequence (common in databases like PostgreSQL).GenerationType.AUTO
: Automatically selects the generation strategy based on the database.
Customizing Columns
Here, we see a field title mapped to a DB column named title, which is non-nullable, and has a length of 100 characters
@Column(nullable = false, length = 100)
private String title;
By default JPA maps fields to columns with the same name. However, the @Column
annotation gives you control over column properties such as:
- name: Define a custom column name.
- nullable: Specifies whether the column can be
null
. - unique: Ensures the column contains unique values.
- length: Sets the maximum length for
String
fields.
Persisted and Transient Fields
By default all the fields are saved to the database as columns even if you don’t define the @Column
annotation. But you have a degree of freedom in defining what and how persistence is set.
@Data
@Entity
public class Task {
//..
// stored in the DB as boolean column "task_complete"
private boolean taskComplete;
// stored in the DB as text column "long_description"
private String longDescription;
// customized column name
@Column(name = "deadline")
private LocalDateTime dueDate;
// Not stored in the DB
@Transient
private boolean isComputing;
// Runtime computed property (not stored in DB)
@Transient
public int getDaysUntilDue() {
return (int) ChronoUnit.DAYS.between(LocalDateTime.now(), this.dueDate);
}
}
In absence of @Column
annotation, each field in camelCase is persisted as DB column in snake_case.
If you want a column to have a different name than the default one, use @Column(name = "custom_column_name")
. Otherwise, JPA/Hibernate handles the column naming automatically.
To avoid persisting fields or methods, use the @Transient
annotation.
Entities Relations
Assume we have two entities: User
and Task
. In the example below, many Task
entities are related to one User
through a foreign key column named "user_id"
on the Task entity.
@Entity
@Table
public class User {
@Id
private long id;
}
@Entity
@Table
public class Task {
@Id
private long id;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
The @JoinColumn
annotation is used to specify the foreign key column that establishes the relationship between two tables. You can customize the foreign key column name and ensure it is non-nullable, enforcing the relationship between the entities.
JPA, Hibernate, or Spring Data JPA?
JPA (Java Persistence API) is a specification, not an implementation that defines a standard for ORM in Java. E.g. it defines annotations like @Entity
, @Id
, @Column
; a query language like JPQL, and entity lifecycle management. It lacks a specification, so you need an ORM framework like Hibernate, EclipseLink or other to use JPA features in your app.
Hibernate is a popular ORM framework and JPA provider. Beyond implementing the JPA specifications, it provides the Hibernate Query Language (HQL), which is an extension of JPQL for advanced query support. It also provides advanced features like: Caching, lazy loading, inheritance mapping, batch processing, and native SQL queries, and advanced configurations, e.g. a fine-grained control over SQL generation.
Spring Data JPA is a Spring Framework project built on top of JPA and Hibernate (or any other JPA provider). Its main features are:
- Integration with Spring dependency injection, transaction management, and other features.
- Repository abstraction: through the JpaRepository you can use common CRUD methods (e.g.,
save()
,findById()
,delete()
). - Query method by convention: which allows to define queries directly in repository method names (e.g.,
findByTitle()
orfindByUserId()
). - Custom query support, supporting JPQL, HQL, and native queries when custom data retrieval is needed.
Conclusion
Spring Data JPA (~ Hibernate ~JPA) annotations provide a powerful way to map Java obejects to DB tables and columns. In this post we explored some of the most used annotations, including: @Entity
, @Table
, @Id
, @GeneratedValue
, @Column
, @ManyToOne
, and @Transient
.
By understanding these annotations, you can take control of your entity mapping ant tailor your DB interactions to meet your application’s needs.
0 Comments