JPA/Hibernate: Configuration and Persistence Context
I- Configuring a JPA Provider like Hibernate with Java Configuration and Annotations
To configure a JPA provider like Hibernate using Java configuration, you typically create a configuration class. Here’s an example of how to do this:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
@Configuration
public class JpaConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/yourdb");
dataSource.setUsername("username");
dataSource.setPassword("password");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("com.example.entity");
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
// Additional properties
em.getJpaPropertyMap().put("hibernate.hbm2ddl.auto", "update");
em.getJpaPropertyMap().put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
em.getJpaPropertyMap().put("hibernate.show_sql", true);
return em;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
II- Persistence Context
The persistence context is a set of entity instances in which for any persistent entity, there is a unique entity instance. It acts as a first-level cache, allowing JPA to keep track of the state of entities.
Key characteristics:
1- Identity: Each entity instance in the persistence context is unique, ensuring that two instances with the same primary key cannot exist simultaneously.
2- Lifecycle: The persistence context manages the lifecycle of entities, including their state transitions (new, managed, detached, removed).
3- Synchronization: As changes are made to the managed entities within the persistence context, those changes are automatically synchronized with the database at the flush time.
III- Persistence Units
In JPA, a persistence unit defines a set of all classes that are related to a specific database. It contains configuration details such as entity classes, database connection properties, and provider information.
A persistence unit is defined in the persistence.xml file, located in the META-INF directory:
<persistence xmlns="https://xmlns.jcp.org/xml/ns/persistence" version="2.1">
<persistence-unit name="myPersistenceUnit">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.example.entity.MyEntity</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/yourdb"/>
<property name="javax.persistence.jdbc.user" value="username"/>
<property name="javax.persistence.jdbc.password" value="password"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
</persistence>
IV- Custom Queries using JPQL
Java Persistence Query Language (JPQL) is an object-oriented query language defined as part of JPA. You can define custom queries using JPQL in the repository interface or by using the EntityManager.
Example of a JPQL query in a repository using Spring Data JPA:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface MyEntityRepository extends JpaRepository<MyEntity, Long> {
@Query("SELECT m FROM MyEntity m WHERE m.name = ?1")
List<MyEntity> findByName(String name);
}
V- Native Queries in JPA
Native queries allow you to write SQL directly within your JPA code. You can use native queries by annotating your method with @Query and specifying nativeQuery = true.
Example:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface MyEntityRepository extends JpaRepository<MyEntity, Long> {
@Query(value = "SELECT * FROM my_entity WHERE name = ?1", nativeQuery = true)
List<MyEntity> findByNameNative(String name);
}
You can also execute native queries using the EntityManager:
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
public class MyEntityDao {
@PersistenceContext
private EntityManager entityManager;
public List<MyEntity> findByNameNative(String name) {
Query query = entityManager.createNativeQuery("SELECT * FROM my_entity WHERE name = ?", MyEntity.class);
query.setParameter(1, name);
return query.getResultList();
}
}
By using native queries, you have the flexibility to leverage database-specific features and optimizations, though at the cost of some of the abstraction that JPQL provides.
NB: When using spaing-data-jpa dependency in Spring boot project, hibernate is auto-provided as the default implementation of JPA provider.