CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-boot--spring-boot-starter-data-jpa

Starter for using Spring Data JPA with Hibernate

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

Spring Boot Starter Data JPA

Spring Boot Starter Data JPA provides comprehensive auto-configuration for integrating Spring Data JPA with Hibernate ORM in Spring Boot applications. This starter automatically configures JPA EntityManagerFactory, transaction management, repository support, and Hibernate-specific settings, enabling developers to build data access layers with minimal configuration.

Package Information

  • Package Name: spring-boot-starter-data-jpa
  • Package Type: maven
  • Maven Coordinates: org.springframework.boot:spring-boot-starter-data-jpa
  • Language: Java
  • Framework: Spring Boot 3.5.0
  • Installation: Add dependency to pom.xml or build.gradle

Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>3.5.0</version>
</dependency>

Gradle:

implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.5.0'

Core Imports

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.boot.autoconfigure.orm.jpa.*;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import jakarta.persistence.*;

Basic Usage

// 1. Define an entity
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    private String email;

    // Getters and setters
}

// 2. Create a repository interface (Spring Data JPA auto-implements it)
public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByName(String name);
    Optional<User> findByEmail(String email);
}

// 3. Use the repository in a service
@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User createUser(String name, String email) {
        User user = new User();
        user.setName(name);
        user.setEmail(email);
        return userRepository.save(user);
    }

    public List<User> findUsersByName(String name) {
        return userRepository.findByName(name);
    }
}

// 4. Configure database connection in application.properties
// spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
// spring.datasource.username=dbuser
// spring.datasource.password=dbpass
// spring.jpa.hibernate.ddl-auto=update
// spring.jpa.show-sql=true

Architecture

The starter provides several layers of auto-configuration:

  • Auto-Configuration Layer: HibernateJpaAutoConfiguration and JpaRepositoriesAutoConfiguration automatically detect dependencies and configure beans
  • JPA Configuration: JpaBaseConfiguration provides EntityManagerFactory, TransactionManager, and related infrastructure beans
  • Repository Support: Spring Data JPA repositories are automatically enabled and implemented
  • Hibernate Integration: Hibernate-specific configuration including naming strategies, DDL handling, and JTA platform
  • Customization Layer: Extensible through properties, customizer interfaces, and bean overrides

Capabilities

Auto-Configuration

The starter automatically configures JPA and Hibernate when dependencies are detected on the classpath.

Auto-Configuration Classes:

@AutoConfiguration(
    after = { DataSourceAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class },
    before = { TransactionAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }
)
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class })
@EnableConfigurationProperties(JpaProperties.class)
@Import(HibernateJpaConfiguration.class)
public class HibernateJpaAutoConfiguration {
    // Auto-configures Hibernate as the JPA provider
    // Imports HibernateJpaConfiguration
}

/**
 * Base configuration for JPA. Provides EntityManagerFactory, TransactionManager,
 * and OpenEntityManagerInView support.
 * Package: org.springframework.boot.autoconfigure.orm.jpa
 */
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(JpaProperties.class)
public abstract class JpaBaseConfiguration {
    /**
     * Create a JpaBaseConfiguration instance.
     *
     * @param dataSource The DataSource to use
     * @param properties JPA configuration properties
     * @param jtaTransactionManager Optional JTA transaction manager
     */
    protected JpaBaseConfiguration(
        DataSource dataSource,
        JpaProperties properties,
        ObjectProvider<JtaTransactionManager> jtaTransactionManager
    ) { }

    /**
     * Configure the JPA transaction manager.
     *
     * @param transactionManagerCustomizers Optional customizers
     * @return The configured PlatformTransactionManager
     */
    @Bean
    @ConditionalOnMissingBean(TransactionManager.class)
    public PlatformTransactionManager transactionManager(
        ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers
    ) { }

    /**
     * Create the primary EntityManagerFactory bean.
     *
     * @param factoryBuilder EntityManagerFactoryBuilder for creating the factory
     * @param persistenceManagedTypes Auto-scanned entity types
     * @return LocalContainerEntityManagerFactoryBean
     */
    @Bean
    @Primary
    @ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
        EntityManagerFactoryBuilder factoryBuilder,
        PersistenceManagedTypes persistenceManagedTypes
    ) { }

    /**
     * Create an EntityManagerFactoryBuilder bean.
     *
     * @param jpaVendorAdapter JPA vendor adapter
     * @param persistenceUnitManager Optional persistence unit manager
     * @param customizers Customizers for the builder
     * @return EntityManagerFactoryBuilder instance
     */
    @Bean
    @ConditionalOnMissingBean
    public EntityManagerFactoryBuilder entityManagerFactoryBuilder(
        JpaVendorAdapter jpaVendorAdapter,
        ObjectProvider<PersistenceUnitManager> persistenceUnitManager,
        ObjectProvider<EntityManagerFactoryBuilderCustomizer> customizers
    ) { }

    /**
     * Return the vendor-specific properties for the given DataSource.
     *
     * @param dataSource The data source
     * @return Map of vendor-specific properties
     * @since 3.4.4
     */
    protected abstract Map<String, Object> getVendorProperties(DataSource dataSource);

    /**
     * Return the vendor-specific properties.
     *
     * @return Map of vendor-specific properties
     * @deprecated since 3.4.4 for removal in 4.0.0 in favor of getVendorProperties(DataSource)
     */
    @Deprecated(since = "3.4.4", forRemoval = true)
    protected Map<String, Object> getVendorProperties() { }

    /**
     * Customize vendor properties before they are used. Allows for post-processing
     * (for example to configure JTA-specific settings).
     *
     * @param vendorProperties The vendor properties to customize
     */
    protected void customizeVendorProperties(Map<String, Object> vendorProperties) { }

    /**
     * Return the JTA transaction manager.
     *
     * @return The transaction manager or null if not using JTA
     */
    protected JtaTransactionManager getJtaTransactionManager() { }

    /**
     * Returns if a JTA PlatformTransactionManager is being used.
     *
     * @return true if a JTA transaction manager is being used
     */
    protected final boolean isJta() { }

    /**
     * Create and configure the JPA vendor adapter bean.
     * Configures the adapter with showSql, database, databasePlatform, and generateDdl settings.
     *
     * @return Configured JPA vendor adapter
     */
    @Bean
    @ConditionalOnMissingBean
    public JpaVendorAdapter jpaVendorAdapter() { }

    /**
     * Return the JpaProperties.
     *
     * @return The JPA properties
     */
    protected final JpaProperties getProperties() { }

    /**
     * Return the DataSource.
     *
     * @return The data source
     */
    protected final DataSource getDataSource() { }

    // Abstract methods that must be implemented by subclasses
    protected abstract AbstractJpaVendorAdapter createJpaVendorAdapter();

    /**
     * Configuration for PersistenceManagedTypes bean.
     * Automatically scans for JPA entities in specified packages.
     * Package: org.springframework.boot.autoconfigure.orm.jpa
     */
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })
    static class PersistenceManagedTypesConfiguration {
        /**
         * Create PersistenceManagedTypes bean by scanning for entity classes.
         * Scans packages from @EntityScan or auto-configuration packages.
         *
         * @param beanFactory Bean factory for accessing configuration
         * @param resourceLoader Resource loader for scanning
         * @param managedClassNameFilter Optional filter for entity class names
         * @return PersistenceManagedTypes containing discovered entity types
         */
        @Bean
        @Primary
        @ConditionalOnMissingBean
        static PersistenceManagedTypes persistenceManagedTypes(
            BeanFactory beanFactory,
            ResourceLoader resourceLoader,
            ObjectProvider<ManagedClassNameFilter> managedClassNameFilter
        ) { }
    }

    /**
     * Configuration for OpenEntityManagerInView pattern support in web applications.
     * Registers interceptor to bind JPA EntityManager to request thread.
     * Package: org.springframework.boot.autoconfigure.orm.jpa
     */
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass(WebMvcConfigurer.class)
    @ConditionalOnMissingBean({ OpenEntityManagerInViewInterceptor.class, OpenEntityManagerInViewFilter.class })
    @ConditionalOnMissingFilterBean(OpenEntityManagerInViewFilter.class)
    @ConditionalOnBooleanProperty(name = "spring.jpa.open-in-view", matchIfMissing = true)
    protected static class JpaWebConfiguration {
        /**
         * Create JpaWebConfiguration instance.
         *
         * @param jpaProperties JPA configuration properties
         */
        protected JpaWebConfiguration(JpaProperties jpaProperties) { }

        /**
         * Create OpenEntityManagerInView interceptor bean.
         * Logs warning if spring.jpa.open-in-view is not explicitly configured.
         *
         * @return OpenEntityManagerInViewInterceptor instance
         */
        @Bean
        public OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor() { }

        /**
         * Create WebMvcConfigurer to register the OpenEntityManagerInView interceptor.
         *
         * @param interceptor The interceptor to register
         * @return WebMvcConfigurer that registers the interceptor
         */
        @Bean
        public WebMvcConfigurer openEntityManagerInViewInterceptorConfigurer(
            OpenEntityManagerInViewInterceptor interceptor
        ) { }
    }
}

/**
 * Auto-configuration for Spring Data JPA repositories.
 * Package: org.springframework.boot.autoconfigure.data.jpa
 */
@AutoConfiguration(after = { HibernateJpaAutoConfiguration.class, TaskExecutionAutoConfiguration.class })
@ConditionalOnBean(DataSource.class)
@ConditionalOnClass(JpaRepository.class)
@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class, JpaRepositoryConfigExtension.class })
@ConditionalOnBooleanProperty(name = "spring.data.jpa.repositories.enabled", matchIfMissing = true)
@Import(JpaRepositoriesImportSelector.class)
public class JpaRepositoriesAutoConfiguration {
    /**
     * Configure EntityManagerFactory bootstrap executor for deferred/lazy initialization.
     *
     * @param taskExecutors Available async task executors
     * @return EntityManagerFactoryBuilderCustomizer
     */
    @Bean
    @Conditional(BootstrapExecutorCondition.class)
    public EntityManagerFactoryBuilderCustomizer entityManagerFactoryBootstrapExecutorCustomizer(
        Map<String, AsyncTaskExecutor> taskExecutors
    ) { }

    /**
     * Import selector that chooses the appropriate repository registrar.
     * Selects EnversRevisionRepositoriesRegistrar if Hibernate Envers is on the classpath,
     * otherwise selects JpaRepositoriesRegistrar.
     */
    static class JpaRepositoriesImportSelector implements ImportSelector {
        /**
         * Select which repository configuration class to import.
         * Returns EnversRevisionRepositoriesRegistrar if Envers is available,
         * otherwise returns JpaRepositoriesRegistrar.
         *
         * @param importingClassMetadata Metadata of the importing class
         * @return Array containing the fully qualified name of the registrar class to import
         */
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) { }
    }
}

Beans Created by Auto-Configuration:

  • entityManagerFactory (LocalContainerEntityManagerFactoryBean) - Primary JPA EntityManagerFactory
  • transactionManager (JpaTransactionManager) - Transaction manager for JPA operations
  • jpaVendorAdapter (HibernateJpaVendorAdapter) - Hibernate vendor adapter
  • entityManagerFactoryBuilder (EntityManagerFactoryBuilder) - Builder for additional EntityManagerFactory instances
  • persistenceManagedTypes (PersistenceManagedTypes) - Auto-scanned entity types
  • openEntityManagerInViewInterceptor (OpenEntityManagerInViewInterceptor) - Request-scoped EntityManager binding (web apps)

Configuration Properties

Configure JPA and Hibernate behavior through application.properties or application.yml.

JPA Properties (spring.jpa.*)

@ConfigurationProperties(prefix = "spring.jpa")
public class JpaProperties {
    // spring.jpa.properties - Additional JPA/Hibernate properties
    private Map<String, String> properties = new HashMap<>();

    // spring.jpa.mapping-resources - Persistence XML mapping files
    private final List<String> mappingResources = new ArrayList<>();

    // spring.jpa.database-platform - Database dialect class name
    private String databasePlatform;

    // spring.jpa.database - Target database enum (AUTO-DETECTED by default)
    private Database database;

    // spring.jpa.generate-ddl - Initialize schema on startup (default: false)
    private boolean generateDdl = false;

    // spring.jpa.show-sql - Enable SQL logging (default: false)
    private boolean showSql = false;

    // spring.jpa.open-in-view - Enable OpenEntityManagerInView pattern (default: true)
    private Boolean openInView;

    // Getter and setter methods
    public Map<String, String> getProperties() { }
    public void setProperties(Map<String, String> properties) { }

    public List<String> getMappingResources() { }

    public String getDatabasePlatform() { }
    public void setDatabasePlatform(String databasePlatform) { }

    public Database getDatabase() { }
    public void setDatabase(Database database) { }

    public boolean isGenerateDdl() { }
    public void setGenerateDdl(boolean generateDdl) { }

    public boolean isShowSql() { }
    public void setShowSql(boolean showSql) { }

    public Boolean getOpenInView() { }
    public void setOpenInView(Boolean openInView) { }

    // Note: spring.jpa.defer-datasource-initialization is not in JpaProperties class
    // It's a separate property handled by Spring Boot's database initialization system
    // spring.jpa.defer-datasource-initialization - Defer DataSource initialization
    // until after EntityManagerFactory beans are created (default: false)
}

Common Configuration Examples:

# Database connection
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=user
spring.datasource.password=pass

# JPA settings
spring.jpa.show-sql=true
spring.jpa.open-in-view=false
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

# Defer datasource initialization until after JPA is ready
# Useful when using script-based initialization with JPA schema generation
spring.jpa.defer-datasource-initialization=false

# Additional Hibernate properties
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.jdbc.batch_size=20

Hibernate Properties (spring.jpa.hibernate.*)

@ConfigurationProperties(prefix = "spring.jpa.hibernate")
public class HibernateProperties {
    // spring.jpa.hibernate.ddl-auto - DDL mode (none, validate, update, create, create-drop)
    private String ddlAuto;

    // Nested naming configuration
    private Naming naming = new Naming();

    /**
     * Get the DDL auto mode.
     *
     * @return The DDL auto mode
     */
    public String getDdlAuto() { }

    /**
     * Set the DDL auto mode.
     *
     * @param ddlAuto The DDL auto mode to set
     */
    public void setDdlAuto(String ddlAuto) { }

    /**
     * Get the naming strategy configuration.
     *
     * @return The naming configuration
     */
    public Naming getNaming() { }

    /**
     * Determine Hibernate configuration properties based on JPA properties and settings.
     *
     * @param jpaProperties Standard JPA properties
     * @param settings Hibernate-specific settings
     * @return Map of Hibernate properties to use
     */
    public Map<String, Object> determineHibernateProperties(
        Map<String, String> jpaProperties,
        HibernateSettings settings
    ) { }

    /**
     * Nested class for Hibernate naming strategy configuration.
     */
    public static class Naming {
        // spring.jpa.hibernate.naming.implicit-strategy - Implicit naming strategy class
        private String implicitStrategy;

        // spring.jpa.hibernate.naming.physical-strategy - Physical naming strategy class
        private String physicalStrategy;

        public String getImplicitStrategy() { }
        public void setImplicitStrategy(String implicitStrategy) { }
        public String getPhysicalStrategy() { }
        public void setPhysicalStrategy(String physicalStrategy) { }
    }
}

DDL Auto Values:

  • none - No schema management
  • validate - Validate schema matches entities (production)
  • update - Update schema to match entities (development)
  • create - Drop and recreate schema on startup
  • create-drop - Drop schema on shutdown

Default Naming Strategies:

  • Implicit: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
  • Physical: org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy

Configuration Examples:

# Schema management
spring.jpa.hibernate.ddl-auto=update

# Custom naming strategies
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy

Repository Properties (spring.data.jpa.repositories.*)

# Enable/disable repository auto-configuration (default: true)
spring.data.jpa.repositories.enabled=true

# Repository bootstrap mode: default, deferred, lazy (default: default)
spring.data.jpa.repositories.bootstrap-mode=deferred

Bootstrap Modes:

  • default - Repositories initialized eagerly at startup
  • deferred - Repositories initialized when first accessed
  • lazy - Repositories initialized on first actual use

Entity Manager Factory Builder

Fluent builder for creating additional EntityManagerFactory instances with common configuration.

package org.springframework.boot.orm.jpa;

public class EntityManagerFactoryBuilder {
    /**
     * Create a new EntityManagerFactoryBuilder instance.
     *
     * @param jpaVendorAdapter JPA vendor adapter
     * @param jpaPropertiesFactory Factory function for creating JPA properties based on DataSource
     * @param persistenceUnitManager Optional persistence unit manager (can be null)
     * @since 3.4.4
     */
    public EntityManagerFactoryBuilder(
        JpaVendorAdapter jpaVendorAdapter,
        Function<DataSource, Map<String, ?>> jpaPropertiesFactory,
        PersistenceUnitManager persistenceUnitManager
    ) { }

    /**
     * Create a new EntityManagerFactoryBuilder instance with persistence unit root location.
     *
     * @param jpaVendorAdapter JPA vendor adapter
     * @param jpaPropertiesFactory Factory function for creating JPA properties based on DataSource
     * @param persistenceUnitManager Optional persistence unit manager (can be null)
     * @param persistenceUnitRootLocation Persistence unit root location (can be null)
     * @since 3.4.4
     */
    public EntityManagerFactoryBuilder(
        JpaVendorAdapter jpaVendorAdapter,
        Function<DataSource, Map<String, ?>> jpaPropertiesFactory,
        PersistenceUnitManager persistenceUnitManager,
        URL persistenceUnitRootLocation
    ) { }

    /**
     * Create a new EntityManagerFactoryBuilder instance.
     *
     * @param jpaVendorAdapter JPA vendor adapter
     * @param jpaProperties Static JPA properties map
     * @param persistenceUnitManager Optional persistence unit manager (can be null)
     * @deprecated since 3.4.4 for removal in 4.0.0 - Use constructor with Function parameter instead
     */
    @Deprecated(since = "3.4.4", forRemoval = true)
    public EntityManagerFactoryBuilder(
        JpaVendorAdapter jpaVendorAdapter,
        Map<String, ?> jpaProperties,
        PersistenceUnitManager persistenceUnitManager
    ) { }

    /**
     * Create a new EntityManagerFactoryBuilder instance with persistence unit root location.
     *
     * @param jpaVendorAdapter JPA vendor adapter
     * @param jpaProperties Static JPA properties map
     * @param persistenceUnitManager Optional persistence unit manager (can be null)
     * @param persistenceUnitRootLocation Persistence unit root location (can be null)
     * @deprecated since 3.4.4 for removal in 4.0.0 - Use constructor with Function parameter instead
     * @since 1.4.1
     */
    @Deprecated(since = "3.4.4", forRemoval = true)
    public EntityManagerFactoryBuilder(
        JpaVendorAdapter jpaVendorAdapter,
        Map<String, ?> jpaProperties,
        PersistenceUnitManager persistenceUnitManager,
        URL persistenceUnitRootLocation
    ) { }

    /**
     * Start building an EntityManagerFactory with a DataSource
     */
    public Builder dataSource(DataSource dataSource) { }

    /**
     * Set async bootstrap executor for background initialization
     */
    public void setBootstrapExecutor(AsyncTaskExecutor bootstrapExecutor) { }

    /**
     * Set persistence unit post processors
     */
    public void setPersistenceUnitPostProcessors(
        PersistenceUnitPostProcessor... postProcessors
    ) { }

    /**
     * Fluent builder for LocalContainerEntityManagerFactoryBean
     */
    public static class Builder {
        /**
         * Set the managed types (entities) for this EntityManagerFactory
         */
        public Builder managedTypes(PersistenceManagedTypes managedTypes) { }

        /**
         * Set packages to scan for entities
         */
        public Builder packages(String... packagesToScan) { }

        /**
         * Set packages to scan using classes as package markers
         *
         * @param basePackageClasses Classes whose packages should be scanned
         * @return Builder for fluent API
         */
        public Builder packages(Class<?>... basePackageClasses) { }

        /**
         * Set persistence unit name
         */
        public Builder persistenceUnit(String persistenceUnitName) { }

        /**
         * Set JPA properties
         */
        public Builder properties(Map<String, ?> properties) { }

        /**
         * Set mapping resources (XML mappings)
         */
        public Builder mappingResources(String... mappingResources) { }

        /**
         * Enable JTA transaction mode
         */
        public Builder jta(boolean jta) { }

        /**
         * Build the LocalContainerEntityManagerFactoryBean
         */
        public LocalContainerEntityManagerFactoryBean build() { }
    }
}

Usage Example - Multiple DataSources:

@Configuration
public class MultiDataSourceConfig {

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSourceProperties primaryDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @Primary
    public DataSource primaryDataSource() {
        return primaryDataSourceProperties()
            .initializeDataSourceBuilder()
            .build();
    }

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("primaryDataSource") DataSource dataSource) {
        return builder
            .dataSource(dataSource)
            .packages("com.example.primary.domain")
            .persistenceUnit("primary")
            .build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSourceProperties secondaryDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    public DataSource secondaryDataSource() {
        return secondaryDataSourceProperties()
            .initializeDataSourceBuilder()
            .build();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("secondaryDataSource") DataSource dataSource) {
        return builder
            .dataSource(dataSource)
            .packages("com.example.secondary.domain")
            .persistenceUnit("secondary")
            .build();
    }
}

Customization Interfaces

Customize Hibernate and EntityManagerFactory configuration through callback interfaces.

HibernatePropertiesCustomizer

package org.springframework.boot.autoconfigure.orm.jpa;

@FunctionalInterface
public interface HibernatePropertiesCustomizer {
    /**
     * Customize Hibernate properties before EntityManagerFactory creation.
     *
     * @param hibernateProperties Map of Hibernate properties to customize
     */
    void customize(Map<String, Object> hibernateProperties);
}

Usage Example:

@Configuration
public class HibernateConfig {

    @Bean
    public HibernatePropertiesCustomizer hibernatePropertiesCustomizer() {
        return (hibernateProperties) -> {
            // Enable Hibernate statistics
            hibernateProperties.put("hibernate.generate_statistics", true);

            // Configure second-level cache
            hibernateProperties.put("hibernate.cache.use_second_level_cache", true);
            hibernateProperties.put("hibernate.cache.region.factory_class",
                "org.hibernate.cache.jcache.JCacheRegionFactory");

            // Configure batch processing
            hibernateProperties.put("hibernate.jdbc.batch_size", 25);
            hibernateProperties.put("hibernate.order_inserts", true);
            hibernateProperties.put("hibernate.order_updates", true);
        };
    }
}

EntityManagerFactoryBuilderCustomizer

package org.springframework.boot.autoconfigure.orm.jpa;

@FunctionalInterface
public interface EntityManagerFactoryBuilderCustomizer {
    /**
     * Customize the EntityManagerFactoryBuilder before it's used.
     *
     * @param builder The EntityManagerFactoryBuilder to customize
     */
    void customize(EntityManagerFactoryBuilder builder);
}

Usage Example:

@Configuration
public class JpaConfig {

    @Bean
    public EntityManagerFactoryBuilderCustomizer entityManagerFactoryBuilderCustomizer() {
        return (builder) -> {
            // Configure async bootstrap for faster startup
            builder.setBootstrapExecutor(asyncTaskExecutor());

            // Add custom persistence unit post processors
            builder.setPersistenceUnitPostProcessors(
                new CustomPersistenceUnitPostProcessor()
            );
        };
    }

    @Bean
    public AsyncTaskExecutor asyncTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setThreadNamePrefix("jpa-bootstrap-");
        executor.initialize();
        return executor;
    }
}

Initialization Order Control

Control EntityManagerFactory initialization order relative to other beans.

package org.springframework.boot.autoconfigure.orm.jpa;

public class EntityManagerFactoryDependsOnPostProcessor
        extends AbstractDependsOnBeanFactoryPostProcessor {

    /**
     * Make EntityManagerFactory depend on specific bean names.
     *
     * @param dependsOn Bean names that EntityManagerFactory should depend on
     */
    public EntityManagerFactoryDependsOnPostProcessor(String... dependsOn) { }

    /**
     * Make EntityManagerFactory depend on beans of specific types.
     *
     * @param dependsOn Bean types that EntityManagerFactory should depend on
     */
    public EntityManagerFactoryDependsOnPostProcessor(Class<?>... dependsOn) { }
}

Usage Example:

@Configuration
public class InitializationOrderConfig {

    /**
     * Ensure EntityManagerFactory initializes after Flyway migrations
     */
    @Bean
    public static EntityManagerFactoryDependsOnPostProcessor
            entityManagerFactoryDependsOnPostProcessor() {
        return new EntityManagerFactoryDependsOnPostProcessor(Flyway.class);
    }
}

Naming Strategies

Customize how entity and column names are mapped to database table and column names.

package org.springframework.boot.orm.jpa.hibernate;

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.ImplicitJoinTableNameSource;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;

/**
 * Spring's default implicit naming strategy.
 * Join tables use format: {owning_table}_{property_name}
 * Identical to ImplicitNamingStrategyJpaCompliantImpl except for join table naming.
 */
public class SpringImplicitNamingStrategy
        extends ImplicitNamingStrategyJpaCompliantImpl {

    /**
     * Determine the implicit name for a join table.
     * Uses format: {owning_physical_table_name}_{association_owning_property_name}
     *
     * @param source The source metadata for the join table
     * @return The identifier for the join table name
     */
    @Override
    public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) { }
}

Providing Custom Naming Strategy:

@Configuration
public class NamingStrategyConfig {

    /**
     * Override the default physical naming strategy
     */
    @Bean
    public PhysicalNamingStrategy physicalNamingStrategy() {
        // Use standard JPA naming (no snake_case conversion)
        return new PhysicalNamingStrategyStandardImpl();
    }

    /**
     * Override the default implicit naming strategy
     */
    @Bean
    public ImplicitNamingStrategy implicitNamingStrategy() {
        return new SpringImplicitNamingStrategy();
    }
}

Or via properties:

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy

Entity Scanning

Control which packages are scanned for JPA entities.

Default Behavior: Auto-scans main application package and sub-packages.

Custom Scanning:

@Configuration
@EntityScan(basePackages = {
    "com.example.domain",
    "com.example.shared.entities"
})
public class EntityScanConfig {
}

Entity Configuration:

@Entity
@Table(name = "products", indexes = {
    @Index(name = "idx_product_sku", columnList = "sku"),
    @Index(name = "idx_product_category", columnList = "category_id")
})
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true, nullable = false, length = 50)
    private String sku;

    @Column(nullable = false)
    private String name;

    @Column(precision = 10, scale = 2)
    private BigDecimal price;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id")
    private Category category;

    @OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Review> reviews = new ArrayList<>();

    // Getters and setters
}

Spring Data JPA Repositories

Create repository interfaces that Spring Data JPA automatically implements.

Repository Interfaces:

// CrudRepository - Basic CRUD operations
public interface CrudRepository<T, ID> extends Repository<T, ID> {
    <S extends T> S save(S entity);
    <S extends T> Iterable<S> saveAll(Iterable<S> entities);
    Optional<T> findById(ID id);
    boolean existsById(ID id);
    Iterable<T> findAll();
    Iterable<T> findAllById(Iterable<ID> ids);
    long count();
    void deleteById(ID id);
    void delete(T entity);
    void deleteAllById(Iterable<? extends ID> ids);
    void deleteAll(Iterable<? extends T> entities);
    void deleteAll();
}

// JpaRepository - Adds JPA-specific methods
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
    List<T> findAll();
    List<T> findAll(Sort sort);
    List<T> findAllById(Iterable<ID> ids);
    <S extends T> List<S> saveAll(Iterable<S> entities);
    void flush();
    <S extends T> S saveAndFlush(S entity);
    <S extends T> List<S> saveAllAndFlush(Iterable<S> entities);
    void deleteInBatch(Iterable<T> entities);
    void deleteAllInBatch(Iterable<T> entities);
    void deleteAllByIdInBatch(Iterable<ID> ids);
    void deleteAllInBatch();
    T getOne(ID id);  // Deprecated, use getReferenceById
    T getReferenceById(ID id);
}

// PagingAndSortingRepository - Pagination and sorting support
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
    Iterable<T> findAll(Sort sort);
    Page<T> findAll(Pageable pageable);
}

Query Methods: Spring Data JPA derives queries from method names.

public interface UserRepository extends JpaRepository<User, Long> {
    // Derived query methods
    List<User> findByName(String name);
    List<User> findByNameAndEmail(String name, String email);
    List<User> findByNameOrEmail(String name, String email);
    List<User> findByAgeBetween(int minAge, int maxAge);
    List<User> findByNameContaining(String namePart);
    List<User> findByNameStartingWith(String prefix);
    List<User> findByNameIgnoreCase(String name);
    List<User> findByOrderByNameAsc();
    Optional<User> findFirstByEmail(String email);

    // With pagination and sorting
    Page<User> findByName(String name, Pageable pageable);
    List<User> findByAge(int age, Sort sort);

    // Count and exists queries
    long countByAge(int age);
    boolean existsByEmail(String email);

    // Delete queries
    long deleteByAge(int age);
    void removeByName(String name);

    // Custom JPQL queries
    @Query("SELECT u FROM User u WHERE u.age > :age")
    List<User> findUsersOlderThan(@Param("age") int age);

    @Query("SELECT u FROM User u WHERE u.name LIKE %:namePart%")
    List<User> searchByName(@Param("namePart") String namePart);

    // Native SQL queries
    @Query(value = "SELECT * FROM users WHERE email = ?1", nativeQuery = true)
    User findByEmailNative(String email);

    // Modifying queries
    @Modifying
    @Query("UPDATE User u SET u.active = :active WHERE u.id = :id")
    int updateActiveStatus(@Param("id") Long id, @Param("active") boolean active);
}

Pagination Example:

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public Page<User> getUsers(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("name").ascending());
        return userRepository.findAll(pageable);
    }

    public Page<User> searchUsers(String name, int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return userRepository.findByName(name, pageable);
    }
}

Transaction Management

JPA transactions are managed automatically through Spring's @Transactional annotation.

Transaction Configuration:

@Service
public class OrderService {
    private final OrderRepository orderRepository;
    private final InventoryService inventoryService;

    public OrderService(OrderRepository orderRepository,
                       InventoryService inventoryService) {
        this.orderRepository = orderRepository;
        this.inventoryService = inventoryService;
    }

    /**
     * Transactional method - changes committed or rolled back together
     */
    @Transactional
    public Order createOrder(OrderRequest request) {
        // Check inventory
        inventoryService.reserveItems(request.getItems());

        // Create order
        Order order = new Order();
        order.setCustomerId(request.getCustomerId());
        order.setItems(request.getItems());
        order.setStatus(OrderStatus.PENDING);

        return orderRepository.save(order);
        // Transaction commits here if no exception thrown
    }

    /**
     * Read-only transaction (optimization)
     */
    @Transactional(readOnly = true)
    public Order getOrder(Long orderId) {
        return orderRepository.findById(orderId)
            .orElseThrow(() -> new OrderNotFoundException(orderId));
    }

    /**
     * Custom transaction configuration
     */
    @Transactional(
        propagation = Propagation.REQUIRES_NEW,
        isolation = Isolation.SERIALIZABLE,
        timeout = 30,
        rollbackFor = BusinessException.class
    )
    public void processRefund(Long orderId) {
        // Process refund in new transaction
    }
}

JTA Integration

JTA platform automatically configured when JTA transaction manager is detected.

package org.springframework.boot.orm.jpa.hibernate;

import jakarta.transaction.TransactionManager;
import jakarta.transaction.UserTransaction;
import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;
import org.springframework.transaction.jta.JtaTransactionManager;

/**
 * Hibernate JTA platform that integrates with Spring's JtaTransactionManager.
 * Automatically configured when JTA is detected.
 */
public class SpringJtaPlatform extends AbstractJtaPlatform {
    /**
     * Create JTA platform with Spring's transaction manager.
     *
     * @param transactionManager The JTA transaction manager
     */
    public SpringJtaPlatform(JtaTransactionManager transactionManager) { }

    /**
     * Locate the TransactionManager from the Spring JtaTransactionManager.
     *
     * @return The JTA TransactionManager
     */
    @Override
    protected TransactionManager locateTransactionManager() { }

    /**
     * Locate the UserTransaction from the Spring JtaTransactionManager.
     *
     * @return The JTA UserTransaction
     */
    @Override
    protected UserTransaction locateUserTransaction() { }
}

Types

// Database enum for spring.jpa.database property
// Package: org.springframework.orm.jpa.vendor (Spring Framework)
public enum Database {
    DEFAULT,
    DB2,
    DERBY,
    H2,
    HANA,
    HSQL,
    INFORMIX,
    MYSQL,
    ORACLE,
    POSTGRESQL,
    SQL_SERVER,
    SYBASE
}

// Bootstrap mode for repository initialization
// Package: org.springframework.data.repository.config (Spring Data Commons)
public enum BootstrapMode {
    DEFAULT,    // Eager initialization at startup
    DEFERRED,   // Initialize when first accessed
    LAZY        // Initialize on first actual use
}

// Hibernate settings container (internal use)
public class HibernateSettings {
    /**
     * Set the DDL auto supplier and return this instance for method chaining.
     *
     * @param ddlAuto Supplier for DDL auto mode
     * @return This HibernateSettings instance
     */
    public HibernateSettings ddlAuto(Supplier<String> ddlAuto) { }

    /**
     * Get the DDL auto mode.
     *
     * @return DDL auto mode or null if not set
     */
    public String getDdlAuto() { }

    /**
     * Set the Hibernate properties customizers and return this instance for method chaining.
     *
     * @param customizers Collection of customizers to apply
     * @return This HibernateSettings instance
     */
    public HibernateSettings hibernatePropertiesCustomizers(
        Collection<HibernatePropertiesCustomizer> customizers
    ) { }

    /**
     * Get the Hibernate properties customizers.
     *
     * @return Collection of customizers
     */
    public Collection<HibernatePropertiesCustomizer> getHibernatePropertiesCustomizers() { }
}

Dependencies

This starter aggregates the following dependencies:

  • spring-boot-starter - Core Spring Boot functionality
  • spring-boot-starter-jdbc - JDBC and DataSource support
  • hibernate-core (org.hibernate.orm) - Hibernate ORM implementation
  • spring-data-jpa (org.springframework.data) - Spring Data JPA repositories
  • spring-aspects (org.springframework) - AOP support for @Transactional

Common Patterns

Testing with @DataJpaTest

@DataJpaTest
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private TestEntityManager entityManager;

    @Test
    void testFindByName() {
        // Given
        User user = new User();
        user.setName("Alice");
        user.setEmail("alice@example.com");
        entityManager.persist(user);
        entityManager.flush();

        // When
        List<User> users = userRepository.findByName("Alice");

        // Then
        assertThat(users).hasSize(1);
        assertThat(users.get(0).getEmail()).isEqualTo("alice@example.com");
    }
}

Auditing

Enable automatic auditing of created/modified dates and users:

@Configuration
@EnableJpaAuditing
public class JpaAuditingConfig {

    @Bean
    public AuditorAware<String> auditorProvider() {
        // Return current user from security context
        return () -> Optional.of(
            SecurityContextHolder.getContext()
                .getAuthentication()
                .getName()
        );
    }
}

@Entity
@EntityListeners(AuditingEntityListener.class)
public class AuditableEntity {

    @CreatedDate
    @Column(nullable = false, updatable = false)
    private Instant createdDate;

    @LastModifiedDate
    private Instant lastModifiedDate;

    @CreatedBy
    @Column(nullable = false, updatable = false)
    private String createdBy;

    @LastModifiedBy
    private String lastModifiedBy;
}

Specifications (Dynamic Queries)

public interface UserRepository extends JpaRepository<User, Long>,
                                        JpaSpecificationExecutor<User> {
}

public class UserSpecifications {

    public static Specification<User> hasName(String name) {
        return (root, query, cb) ->
            name == null ? null : cb.equal(root.get("name"), name);
    }

    public static Specification<User> isActive() {
        return (root, query, cb) -> cb.isTrue(root.get("active"));
    }

    public static Specification<User> ageGreaterThan(int age) {
        return (root, query, cb) -> cb.greaterThan(root.get("age"), age);
    }
}

// Usage
@Service
public class UserSearchService {
    private final UserRepository userRepository;

    public List<User> searchUsers(String name, Integer minAge, Boolean active) {
        Specification<User> spec = Specification.where(null);

        if (name != null) {
            spec = spec.and(UserSpecifications.hasName(name));
        }
        if (minAge != null) {
            spec = spec.and(UserSpecifications.ageGreaterThan(minAge));
        }
        if (Boolean.TRUE.equals(active)) {
            spec = spec.and(UserSpecifications.isActive());
        }

        return userRepository.findAll(spec);
    }
}
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.springframework.boot/spring-boot-starter-data-jpa@3.5.x
Publish Source
CLI
Badge
tessl/maven-org-springframework-boot--spring-boot-starter-data-jpa badge