Originally published on January 31, 2015

Spring Data JPA

How do we implement database relationships using spring data JPA?

There are a lot of real-world objects that impact a business case. Of those, a few of them impact a specific use case of a business. Once we identify the real-world objects that impact the specific business use case, then a database model is created. To be more precise, an entity-relationship diagram is made from that information. There would be a lot of relationships among those business objects or entities, which have to be implemented in the software.

You might also like: Spring Boot With Spring Data JPA

A relationship works by matching data in key columns — usually columns with the same name in both tables. In most cases, the relationship matches the primary key from one table, which provides a unique identifier for each row, with an entry in the foreign key in the other table.

Let’s say we are working for a telecommunication vendor who wants to track his customers who have been shifting from one location to another and asking for a new connection every time they move to a new location.

So, in this case, a customer will be associated with an account. This account is tied to a specific location, which has the zip code. This seems to be that one customer can have only one account at a given location. If the same customer is allowed to have multiple accounts at a location, then it means that one customer can have multiple accounts at a location.

This is an example of a one-to-many relationship. Similarly, that location can have multiple accounts. This leads to a many-to-one relationship between account and location. Since the same customer is tied to the location, it is a one-to-one relationship between them. There are three types of relationships between tables. The type of relationship that is created depends on how the related columns are defined.

1. One-to-Many Relationship

A one-to-many relationship is the most common type of relationship. In this type of relationship, a row in table A can have many matching rows in table B, but a row in table B can have only one matching row in table A. In the above example, a customer can have many accounts for a given location. So it’s a one-to-many relationship.

2. Many-to-Many Relationships

In a many-to-many relationship, a row in table A can have many matching rows in table B and vice versa. In the above example, one customer can have many accounts at one location. So there can be many-to-many relationships in between accounts and customers, provided a new customer id is given for a new account and is not tied to the same customer id. One can also maintain such a relationship by defining a third table, called a junction table, whose primary key consists of the foreign keys from both table A and table B. This might not be really required.

3. One-to-One Relationships

In a one-to-one relationship, a row in table A can have no more than one matching row in table B and vice versa. A one-to-one relationship is created if both of the related columns are primary keys or have unique constraints. So in the above example, one customer can be tied to one location.

There are multiple ways of solving this in Java space. The following are the technologies:

1. Plain JDBC using a JDBC driver

2. Spring Data JPA using Hibernate

3. Spring JDBC which is essentially plain JDBC in itself

4. Giving the objects to RDBMS with data to persist it. Essentially, it’s the RDBMS layer that can take care of the persistence.

In this article, I will be talking about how to persist this using spring data.

Step 1: Use tools like STS, which has built-in provision to create an entity object.





Then you would see:





Enter “JPA Project” to create a JPA Project. Here you can enter the value as per your understanding.





Click next unless you want to do some configurations.





Try to add a connection to a new connection.





Pick the database type.





Enter the connection details.





Upon completion of this, Spring data JPA will create the Java files for you, which are required for the execution of the project. These Java files will have the entity and the column mappings. Please make sure that you have the @Id mapping or you will have a hibernate exception.

Now, in order to implement the one-to-many relationships, make sure that you have the line defined in the customer class.

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true,mappedBy="account")

Here, the @OneToMany relationship makes sure that the one customer has many accounts. Now in the account class, make sure that you have:

@ManyToOne(cascade=CascadeType.ALL)

@JoinColumn(name=" ACCOUNT_ID",nullable=false)

private Customer customer;

This ensures that the many-to-one relationship is established.

If you are creating a new child record for an existing parent, it’s essential to associate the child with the parent. You can create a record in the child table by giving a parent id. But Spring Data JPA asks for the parent record so as to be able to create the child.

Transactions and Spring Data JPA

It’s quite essential to understand how transactions and spring data JPA work together. Transactions have the following propagation levels:

· MANDATORY Support a current transaction; throw an exception if none exists. · NESTED Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else. · NEVER Execute non-transactionally, throw an exception if a transaction exists. · NOT_SUPPORTED Execute non-transactionally, suspend the current transaction if one exists. · REQUIRED Support a current transaction, create a new one if none exists. · REQUIRES_NEW Create a new transaction, and suspend the current transaction if one exists. · SUPPORTS Support a current transaction, execute non-transactionally if none exists.

Transactions have the following isolation levels:

· DEFAULT Use the default isolation level of the underlying datastore. · READ_COMMITTED A constant indicating that dirty reads are prevented; non-repeatable reads and phantom reads can occur. · READ_UNCOMMITTED A constant indicating that dirty reads, non-repeatable reads, and phantom reads can occur. · REPEATABLE_READ A constant indicating that dirty reads and non-repeatable reads are prevented; phantom reads can occur. · SERIALIZABLE A constant indicating that dirty reads, non-repeatable reads, and phantom reads are prevented.

Now when you are wanting to call the transactions, please make sure that the isolation levels that have been used are correct. Also, make sure that the propagation level over the method is done correctly.

How to achieve the batch insert using spring data JPA?

The JpaRepository has methods that have the provision to accept a collection of objects. This collection can be used to persist the records. Please do not assume that this is a batch insert. It’s not. The <S extends T> List<S> save(Iterable<S> entities) and actually iterates through the collection and saves record one by one.

Conclusion

After going through this article, you can replicate the entity-relationship diagram into Spring Data JPA entities and appropriately use the transactions to save them into the database. By using spring data JPA, you leave the responsibility of the database with the Spring JPA API. This way, you can focus on the business functionality more than on the technical complexities of the database relationships.

Further Reading

Using the Spring Data JPA

Introduction to Spring Data and Spring Data JPA