Things you should know while using JPA
Omar Ismail
Senior Software Engineer @ Digitinary | Java & Spring Expert ? | AWS & Microservices Architect ? | FinTech & Open Banking Innovator ?? | Digital Payments Expert ?? | Top 200 IT Content Creator in Jordan ?? | 40K+ ??
Thanks to the original writer and article :
https://medium.com/@amitkumar88265/ten-things-you-should-know-while-using-jpa-89ec52d09d7d
All the examples in this blog have been created with a spring boot project with spring data JPA in Java.
Let us understand that with an example given below:-
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Integer age;
@ManyToMany()
private List<Address> addresses;
}
@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String city;
private String state;
private String country;
}
@Transactional
@Service
public class PersonService {
@Autowired
private PersonRepository personRepository;
@Autowired
private AddressRepository addressRepository;
public void update() {
Person person = personRepository.findByName(“test”);
Address address = new Address();
Address saved = addressRepository.save(address );
person.getAddresses().add(saved);
}
}
Queries fired are :-
So what happens above is that first select query is fired to load person by name and second select query to load all addresses associated with the person which already has five addresses associated with that. After that one new address is created. And the entire address of that person is dropped and the concerned objects(5+1 new address) are inserted again. We can easily avoid it if we use Set instead of List. Same goes when we delete an item from the list.
3. For write operation we should load entity classes from DB but for read operation always use projection unless it is necessary to load entity class. The reason behind this is that when we load entity objects from DB then JPA starts the entity management lifecycle to detect changes on entities and at the end of transaction it flushes out all changes to DB, resulting in poor performance during read operation.
4. From point number 4, it is evident that JPA entity management lifecycles always do dirty checks to detect changes done on entities in that transaction, so need to use?save(Entity entity)?during update of any entity object.
@Transactional
@Service
public class PersonService {
public void updateName(Long id, String name) {
Person person = personRepository.findById(id)
.orElseThrow(EntityNotFoundException::new);
person.setName(name);
personRepository.save(person);// no need of it
}
}
5. In a bidirectional one-2-one mapping, always use?mappedBy?in one of the classes, otherwise JPA will create foreign keys in both tables.
You can see the image below in which alter table queries to create foreign keys on both tables are fired.
Here we have removed one foreign key by using the?mappedBy?attribute.
6. Always use?@JoinColum?on unidirectional one-2-many relationships, otherwise JPA will create a linking table instead of storing foreign keys in many side of the relationship.
A Linking table?person_addresses?is created when?@JoinColumn?is?not used.
No Linking table but instead a foreign key in the address table has been created when?@JoinColumn?is used.
7. In a bidirectional one-2-many mapping always use?mappedBy?on the inverse side of relationships, otherwise JPA will create a linking table instead of storing foreign keys in many side of the relationship.
A Linking table?person_addresses?has been created when?mappedBy?is not used.
No Linking table but instead a foreign key in the address table has been created when?mappedBy?is used.
8. Always use?@JoinTable?and?mappedBy?on bidirectional many-2-many relationships, otherwise a two linking table will be created instead of two tables and one linking table.
Two linking tables are created when bi-directional @ManyToMany relationship has been created without?@JoinTable.
Only one linking table is created when?@JoinTable?is used.
9. Don’t use?@Column?on fields of entity classes if you don’t want to specify some other properties. It makes no sense, your application will run smoothly without it as well.
@Entity
public class Sample {
@Column // no need of this annotation
private String value;
}
10. If class is final or has a private no-args constructor then lazy load won’t work.
Thanks for reading.
Keep Learning!
?? Tech Lead | Business Analyst | HRIS Specialist HCM Oracle ??
2 年Ihsane El
Software Engineer ?? && Instructor at Cybernet LLC
2 年??