Starter for using Spring Data JPA with Hibernate
npx @tessl/cli install tessl/maven-org-springframework-boot--spring-boot-starter-data-jpa@3.5.00
# Spring Boot Starter Data JPA
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: spring-boot-starter-data-jpa
7
- **Package Type**: maven
8
- **Maven Coordinates**: org.springframework.boot:spring-boot-starter-data-jpa
9
- **Language**: Java
10
- **Framework**: Spring Boot 3.5.0
11
- **Installation**: Add dependency to `pom.xml` or `build.gradle`
12
13
**Maven**:
14
```xml
15
<dependency>
16
<groupId>org.springframework.boot</groupId>
17
<artifactId>spring-boot-starter-data-jpa</artifactId>
18
<version>3.5.0</version>
19
</dependency>
20
```
21
22
**Gradle**:
23
```gradle
24
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.5.0'
25
```
26
27
## Core Imports
28
29
```java
30
import org.springframework.data.jpa.repository.JpaRepository;
31
import org.springframework.boot.autoconfigure.orm.jpa.*;
32
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
33
import jakarta.persistence.*;
34
```
35
36
## Basic Usage
37
38
```java
39
// 1. Define an entity
40
@Entity
41
@Table(name = "users")
42
public class User {
43
@Id
44
@GeneratedValue(strategy = GenerationType.IDENTITY)
45
private Long id;
46
47
@Column(nullable = false)
48
private String name;
49
50
private String email;
51
52
// Getters and setters
53
}
54
55
// 2. Create a repository interface (Spring Data JPA auto-implements it)
56
public interface UserRepository extends JpaRepository<User, Long> {
57
List<User> findByName(String name);
58
Optional<User> findByEmail(String email);
59
}
60
61
// 3. Use the repository in a service
62
@Service
63
public class UserService {
64
private final UserRepository userRepository;
65
66
public UserService(UserRepository userRepository) {
67
this.userRepository = userRepository;
68
}
69
70
public User createUser(String name, String email) {
71
User user = new User();
72
user.setName(name);
73
user.setEmail(email);
74
return userRepository.save(user);
75
}
76
77
public List<User> findUsersByName(String name) {
78
return userRepository.findByName(name);
79
}
80
}
81
82
// 4. Configure database connection in application.properties
83
// spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
84
// spring.datasource.username=dbuser
85
// spring.datasource.password=dbpass
86
// spring.jpa.hibernate.ddl-auto=update
87
// spring.jpa.show-sql=true
88
```
89
90
## Architecture
91
92
The starter provides several layers of auto-configuration:
93
94
- **Auto-Configuration Layer**: `HibernateJpaAutoConfiguration` and `JpaRepositoriesAutoConfiguration` automatically detect dependencies and configure beans
95
- **JPA Configuration**: `JpaBaseConfiguration` provides EntityManagerFactory, TransactionManager, and related infrastructure beans
96
- **Repository Support**: Spring Data JPA repositories are automatically enabled and implemented
97
- **Hibernate Integration**: Hibernate-specific configuration including naming strategies, DDL handling, and JTA platform
98
- **Customization Layer**: Extensible through properties, customizer interfaces, and bean overrides
99
100
## Capabilities
101
102
### Auto-Configuration
103
104
The starter automatically configures JPA and Hibernate when dependencies are detected on the classpath.
105
106
**Auto-Configuration Classes**:
107
108
```java { .api }
109
@AutoConfiguration(
110
after = { DataSourceAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class },
111
before = { TransactionAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }
112
)
113
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class })
114
@EnableConfigurationProperties(JpaProperties.class)
115
@Import(HibernateJpaConfiguration.class)
116
public class HibernateJpaAutoConfiguration {
117
// Auto-configures Hibernate as the JPA provider
118
// Imports HibernateJpaConfiguration
119
}
120
121
/**
122
* Base configuration for JPA. Provides EntityManagerFactory, TransactionManager,
123
* and OpenEntityManagerInView support.
124
* Package: org.springframework.boot.autoconfigure.orm.jpa
125
*/
126
@Configuration(proxyBeanMethods = false)
127
@EnableConfigurationProperties(JpaProperties.class)
128
public abstract class JpaBaseConfiguration {
129
/**
130
* Create a JpaBaseConfiguration instance.
131
*
132
* @param dataSource The DataSource to use
133
* @param properties JPA configuration properties
134
* @param jtaTransactionManager Optional JTA transaction manager
135
*/
136
protected JpaBaseConfiguration(
137
DataSource dataSource,
138
JpaProperties properties,
139
ObjectProvider<JtaTransactionManager> jtaTransactionManager
140
) { }
141
142
/**
143
* Configure the JPA transaction manager.
144
*
145
* @param transactionManagerCustomizers Optional customizers
146
* @return The configured PlatformTransactionManager
147
*/
148
@Bean
149
@ConditionalOnMissingBean(TransactionManager.class)
150
public PlatformTransactionManager transactionManager(
151
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers
152
) { }
153
154
/**
155
* Create the primary EntityManagerFactory bean.
156
*
157
* @param factoryBuilder EntityManagerFactoryBuilder for creating the factory
158
* @param persistenceManagedTypes Auto-scanned entity types
159
* @return LocalContainerEntityManagerFactoryBean
160
*/
161
@Bean
162
@Primary
163
@ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })
164
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
165
EntityManagerFactoryBuilder factoryBuilder,
166
PersistenceManagedTypes persistenceManagedTypes
167
) { }
168
169
/**
170
* Create an EntityManagerFactoryBuilder bean.
171
*
172
* @param jpaVendorAdapter JPA vendor adapter
173
* @param persistenceUnitManager Optional persistence unit manager
174
* @param customizers Customizers for the builder
175
* @return EntityManagerFactoryBuilder instance
176
*/
177
@Bean
178
@ConditionalOnMissingBean
179
public EntityManagerFactoryBuilder entityManagerFactoryBuilder(
180
JpaVendorAdapter jpaVendorAdapter,
181
ObjectProvider<PersistenceUnitManager> persistenceUnitManager,
182
ObjectProvider<EntityManagerFactoryBuilderCustomizer> customizers
183
) { }
184
185
/**
186
* Return the vendor-specific properties for the given DataSource.
187
*
188
* @param dataSource The data source
189
* @return Map of vendor-specific properties
190
* @since 3.4.4
191
*/
192
protected abstract Map<String, Object> getVendorProperties(DataSource dataSource);
193
194
/**
195
* Return the vendor-specific properties.
196
*
197
* @return Map of vendor-specific properties
198
* @deprecated since 3.4.4 for removal in 4.0.0 in favor of getVendorProperties(DataSource)
199
*/
200
@Deprecated(since = "3.4.4", forRemoval = true)
201
protected Map<String, Object> getVendorProperties() { }
202
203
/**
204
* Customize vendor properties before they are used. Allows for post-processing
205
* (for example to configure JTA-specific settings).
206
*
207
* @param vendorProperties The vendor properties to customize
208
*/
209
protected void customizeVendorProperties(Map<String, Object> vendorProperties) { }
210
211
/**
212
* Return the JTA transaction manager.
213
*
214
* @return The transaction manager or null if not using JTA
215
*/
216
protected JtaTransactionManager getJtaTransactionManager() { }
217
218
/**
219
* Returns if a JTA PlatformTransactionManager is being used.
220
*
221
* @return true if a JTA transaction manager is being used
222
*/
223
protected final boolean isJta() { }
224
225
/**
226
* Create and configure the JPA vendor adapter bean.
227
* Configures the adapter with showSql, database, databasePlatform, and generateDdl settings.
228
*
229
* @return Configured JPA vendor adapter
230
*/
231
@Bean
232
@ConditionalOnMissingBean
233
public JpaVendorAdapter jpaVendorAdapter() { }
234
235
/**
236
* Return the JpaProperties.
237
*
238
* @return The JPA properties
239
*/
240
protected final JpaProperties getProperties() { }
241
242
/**
243
* Return the DataSource.
244
*
245
* @return The data source
246
*/
247
protected final DataSource getDataSource() { }
248
249
// Abstract methods that must be implemented by subclasses
250
protected abstract AbstractJpaVendorAdapter createJpaVendorAdapter();
251
252
/**
253
* Configuration for PersistenceManagedTypes bean.
254
* Automatically scans for JPA entities in specified packages.
255
* Package: org.springframework.boot.autoconfigure.orm.jpa
256
*/
257
@Configuration(proxyBeanMethods = false)
258
@ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })
259
static class PersistenceManagedTypesConfiguration {
260
/**
261
* Create PersistenceManagedTypes bean by scanning for entity classes.
262
* Scans packages from @EntityScan or auto-configuration packages.
263
*
264
* @param beanFactory Bean factory for accessing configuration
265
* @param resourceLoader Resource loader for scanning
266
* @param managedClassNameFilter Optional filter for entity class names
267
* @return PersistenceManagedTypes containing discovered entity types
268
*/
269
@Bean
270
@Primary
271
@ConditionalOnMissingBean
272
static PersistenceManagedTypes persistenceManagedTypes(
273
BeanFactory beanFactory,
274
ResourceLoader resourceLoader,
275
ObjectProvider<ManagedClassNameFilter> managedClassNameFilter
276
) { }
277
}
278
279
/**
280
* Configuration for OpenEntityManagerInView pattern support in web applications.
281
* Registers interceptor to bind JPA EntityManager to request thread.
282
* Package: org.springframework.boot.autoconfigure.orm.jpa
283
*/
284
@Configuration(proxyBeanMethods = false)
285
@ConditionalOnWebApplication(type = Type.SERVLET)
286
@ConditionalOnClass(WebMvcConfigurer.class)
287
@ConditionalOnMissingBean({ OpenEntityManagerInViewInterceptor.class, OpenEntityManagerInViewFilter.class })
288
@ConditionalOnMissingFilterBean(OpenEntityManagerInViewFilter.class)
289
@ConditionalOnBooleanProperty(name = "spring.jpa.open-in-view", matchIfMissing = true)
290
protected static class JpaWebConfiguration {
291
/**
292
* Create JpaWebConfiguration instance.
293
*
294
* @param jpaProperties JPA configuration properties
295
*/
296
protected JpaWebConfiguration(JpaProperties jpaProperties) { }
297
298
/**
299
* Create OpenEntityManagerInView interceptor bean.
300
* Logs warning if spring.jpa.open-in-view is not explicitly configured.
301
*
302
* @return OpenEntityManagerInViewInterceptor instance
303
*/
304
@Bean
305
public OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor() { }
306
307
/**
308
* Create WebMvcConfigurer to register the OpenEntityManagerInView interceptor.
309
*
310
* @param interceptor The interceptor to register
311
* @return WebMvcConfigurer that registers the interceptor
312
*/
313
@Bean
314
public WebMvcConfigurer openEntityManagerInViewInterceptorConfigurer(
315
OpenEntityManagerInViewInterceptor interceptor
316
) { }
317
}
318
}
319
320
/**
321
* Auto-configuration for Spring Data JPA repositories.
322
* Package: org.springframework.boot.autoconfigure.data.jpa
323
*/
324
@AutoConfiguration(after = { HibernateJpaAutoConfiguration.class, TaskExecutionAutoConfiguration.class })
325
@ConditionalOnBean(DataSource.class)
326
@ConditionalOnClass(JpaRepository.class)
327
@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class, JpaRepositoryConfigExtension.class })
328
@ConditionalOnBooleanProperty(name = "spring.data.jpa.repositories.enabled", matchIfMissing = true)
329
@Import(JpaRepositoriesImportSelector.class)
330
public class JpaRepositoriesAutoConfiguration {
331
/**
332
* Configure EntityManagerFactory bootstrap executor for deferred/lazy initialization.
333
*
334
* @param taskExecutors Available async task executors
335
* @return EntityManagerFactoryBuilderCustomizer
336
*/
337
@Bean
338
@Conditional(BootstrapExecutorCondition.class)
339
public EntityManagerFactoryBuilderCustomizer entityManagerFactoryBootstrapExecutorCustomizer(
340
Map<String, AsyncTaskExecutor> taskExecutors
341
) { }
342
343
/**
344
* Import selector that chooses the appropriate repository registrar.
345
* Selects EnversRevisionRepositoriesRegistrar if Hibernate Envers is on the classpath,
346
* otherwise selects JpaRepositoriesRegistrar.
347
*/
348
static class JpaRepositoriesImportSelector implements ImportSelector {
349
/**
350
* Select which repository configuration class to import.
351
* Returns EnversRevisionRepositoriesRegistrar if Envers is available,
352
* otherwise returns JpaRepositoriesRegistrar.
353
*
354
* @param importingClassMetadata Metadata of the importing class
355
* @return Array containing the fully qualified name of the registrar class to import
356
*/
357
@Override
358
public String[] selectImports(AnnotationMetadata importingClassMetadata) { }
359
}
360
}
361
```
362
363
**Beans Created by Auto-Configuration**:
364
365
- `entityManagerFactory` (LocalContainerEntityManagerFactoryBean) - Primary JPA EntityManagerFactory
366
- `transactionManager` (JpaTransactionManager) - Transaction manager for JPA operations
367
- `jpaVendorAdapter` (HibernateJpaVendorAdapter) - Hibernate vendor adapter
368
- `entityManagerFactoryBuilder` (EntityManagerFactoryBuilder) - Builder for additional EntityManagerFactory instances
369
- `persistenceManagedTypes` (PersistenceManagedTypes) - Auto-scanned entity types
370
- `openEntityManagerInViewInterceptor` (OpenEntityManagerInViewInterceptor) - Request-scoped EntityManager binding (web apps)
371
372
### Configuration Properties
373
374
Configure JPA and Hibernate behavior through `application.properties` or `application.yml`.
375
376
#### JPA Properties (spring.jpa.*)
377
378
```java { .api }
379
@ConfigurationProperties(prefix = "spring.jpa")
380
public class JpaProperties {
381
// spring.jpa.properties - Additional JPA/Hibernate properties
382
private Map<String, String> properties = new HashMap<>();
383
384
// spring.jpa.mapping-resources - Persistence XML mapping files
385
private final List<String> mappingResources = new ArrayList<>();
386
387
// spring.jpa.database-platform - Database dialect class name
388
private String databasePlatform;
389
390
// spring.jpa.database - Target database enum (AUTO-DETECTED by default)
391
private Database database;
392
393
// spring.jpa.generate-ddl - Initialize schema on startup (default: false)
394
private boolean generateDdl = false;
395
396
// spring.jpa.show-sql - Enable SQL logging (default: false)
397
private boolean showSql = false;
398
399
// spring.jpa.open-in-view - Enable OpenEntityManagerInView pattern (default: true)
400
private Boolean openInView;
401
402
// Getter and setter methods
403
public Map<String, String> getProperties() { }
404
public void setProperties(Map<String, String> properties) { }
405
406
public List<String> getMappingResources() { }
407
408
public String getDatabasePlatform() { }
409
public void setDatabasePlatform(String databasePlatform) { }
410
411
public Database getDatabase() { }
412
public void setDatabase(Database database) { }
413
414
public boolean isGenerateDdl() { }
415
public void setGenerateDdl(boolean generateDdl) { }
416
417
public boolean isShowSql() { }
418
public void setShowSql(boolean showSql) { }
419
420
public Boolean getOpenInView() { }
421
public void setOpenInView(Boolean openInView) { }
422
423
// Note: spring.jpa.defer-datasource-initialization is not in JpaProperties class
424
// It's a separate property handled by Spring Boot's database initialization system
425
// spring.jpa.defer-datasource-initialization - Defer DataSource initialization
426
// until after EntityManagerFactory beans are created (default: false)
427
}
428
```
429
430
**Common Configuration Examples**:
431
432
```properties
433
# Database connection
434
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
435
spring.datasource.username=user
436
spring.datasource.password=pass
437
438
# JPA settings
439
spring.jpa.show-sql=true
440
spring.jpa.open-in-view=false
441
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
442
443
# Defer datasource initialization until after JPA is ready
444
# Useful when using script-based initialization with JPA schema generation
445
spring.jpa.defer-datasource-initialization=false
446
447
# Additional Hibernate properties
448
spring.jpa.properties.hibernate.format_sql=true
449
spring.jpa.properties.hibernate.use_sql_comments=true
450
spring.jpa.properties.hibernate.jdbc.batch_size=20
451
```
452
453
#### Hibernate Properties (spring.jpa.hibernate.*)
454
455
```java { .api }
456
@ConfigurationProperties(prefix = "spring.jpa.hibernate")
457
public class HibernateProperties {
458
// spring.jpa.hibernate.ddl-auto - DDL mode (none, validate, update, create, create-drop)
459
private String ddlAuto;
460
461
// Nested naming configuration
462
private Naming naming = new Naming();
463
464
/**
465
* Get the DDL auto mode.
466
*
467
* @return The DDL auto mode
468
*/
469
public String getDdlAuto() { }
470
471
/**
472
* Set the DDL auto mode.
473
*
474
* @param ddlAuto The DDL auto mode to set
475
*/
476
public void setDdlAuto(String ddlAuto) { }
477
478
/**
479
* Get the naming strategy configuration.
480
*
481
* @return The naming configuration
482
*/
483
public Naming getNaming() { }
484
485
/**
486
* Determine Hibernate configuration properties based on JPA properties and settings.
487
*
488
* @param jpaProperties Standard JPA properties
489
* @param settings Hibernate-specific settings
490
* @return Map of Hibernate properties to use
491
*/
492
public Map<String, Object> determineHibernateProperties(
493
Map<String, String> jpaProperties,
494
HibernateSettings settings
495
) { }
496
497
/**
498
* Nested class for Hibernate naming strategy configuration.
499
*/
500
public static class Naming {
501
// spring.jpa.hibernate.naming.implicit-strategy - Implicit naming strategy class
502
private String implicitStrategy;
503
504
// spring.jpa.hibernate.naming.physical-strategy - Physical naming strategy class
505
private String physicalStrategy;
506
507
public String getImplicitStrategy() { }
508
public void setImplicitStrategy(String implicitStrategy) { }
509
public String getPhysicalStrategy() { }
510
public void setPhysicalStrategy(String physicalStrategy) { }
511
}
512
}
513
```
514
515
**DDL Auto Values**:
516
- `none` - No schema management
517
- `validate` - Validate schema matches entities (production)
518
- `update` - Update schema to match entities (development)
519
- `create` - Drop and recreate schema on startup
520
- `create-drop` - Drop schema on shutdown
521
522
**Default Naming Strategies**:
523
- Implicit: `org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy`
524
- Physical: `org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy`
525
526
**Configuration Examples**:
527
528
```properties
529
# Schema management
530
spring.jpa.hibernate.ddl-auto=update
531
532
# Custom naming strategies
533
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
534
spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
535
```
536
537
#### Repository Properties (spring.data.jpa.repositories.*)
538
539
```properties
540
# Enable/disable repository auto-configuration (default: true)
541
spring.data.jpa.repositories.enabled=true
542
543
# Repository bootstrap mode: default, deferred, lazy (default: default)
544
spring.data.jpa.repositories.bootstrap-mode=deferred
545
```
546
547
**Bootstrap Modes**:
548
- `default` - Repositories initialized eagerly at startup
549
- `deferred` - Repositories initialized when first accessed
550
- `lazy` - Repositories initialized on first actual use
551
552
### Entity Manager Factory Builder
553
554
Fluent builder for creating additional EntityManagerFactory instances with common configuration.
555
556
```java { .api }
557
package org.springframework.boot.orm.jpa;
558
559
public class EntityManagerFactoryBuilder {
560
/**
561
* Create a new EntityManagerFactoryBuilder instance.
562
*
563
* @param jpaVendorAdapter JPA vendor adapter
564
* @param jpaPropertiesFactory Factory function for creating JPA properties based on DataSource
565
* @param persistenceUnitManager Optional persistence unit manager (can be null)
566
* @since 3.4.4
567
*/
568
public EntityManagerFactoryBuilder(
569
JpaVendorAdapter jpaVendorAdapter,
570
Function<DataSource, Map<String, ?>> jpaPropertiesFactory,
571
PersistenceUnitManager persistenceUnitManager
572
) { }
573
574
/**
575
* Create a new EntityManagerFactoryBuilder instance with persistence unit root location.
576
*
577
* @param jpaVendorAdapter JPA vendor adapter
578
* @param jpaPropertiesFactory Factory function for creating JPA properties based on DataSource
579
* @param persistenceUnitManager Optional persistence unit manager (can be null)
580
* @param persistenceUnitRootLocation Persistence unit root location (can be null)
581
* @since 3.4.4
582
*/
583
public EntityManagerFactoryBuilder(
584
JpaVendorAdapter jpaVendorAdapter,
585
Function<DataSource, Map<String, ?>> jpaPropertiesFactory,
586
PersistenceUnitManager persistenceUnitManager,
587
URL persistenceUnitRootLocation
588
) { }
589
590
/**
591
* Create a new EntityManagerFactoryBuilder instance.
592
*
593
* @param jpaVendorAdapter JPA vendor adapter
594
* @param jpaProperties Static JPA properties map
595
* @param persistenceUnitManager Optional persistence unit manager (can be null)
596
* @deprecated since 3.4.4 for removal in 4.0.0 - Use constructor with Function parameter instead
597
*/
598
@Deprecated(since = "3.4.4", forRemoval = true)
599
public EntityManagerFactoryBuilder(
600
JpaVendorAdapter jpaVendorAdapter,
601
Map<String, ?> jpaProperties,
602
PersistenceUnitManager persistenceUnitManager
603
) { }
604
605
/**
606
* Create a new EntityManagerFactoryBuilder instance with persistence unit root location.
607
*
608
* @param jpaVendorAdapter JPA vendor adapter
609
* @param jpaProperties Static JPA properties map
610
* @param persistenceUnitManager Optional persistence unit manager (can be null)
611
* @param persistenceUnitRootLocation Persistence unit root location (can be null)
612
* @deprecated since 3.4.4 for removal in 4.0.0 - Use constructor with Function parameter instead
613
* @since 1.4.1
614
*/
615
@Deprecated(since = "3.4.4", forRemoval = true)
616
public EntityManagerFactoryBuilder(
617
JpaVendorAdapter jpaVendorAdapter,
618
Map<String, ?> jpaProperties,
619
PersistenceUnitManager persistenceUnitManager,
620
URL persistenceUnitRootLocation
621
) { }
622
623
/**
624
* Start building an EntityManagerFactory with a DataSource
625
*/
626
public Builder dataSource(DataSource dataSource) { }
627
628
/**
629
* Set async bootstrap executor for background initialization
630
*/
631
public void setBootstrapExecutor(AsyncTaskExecutor bootstrapExecutor) { }
632
633
/**
634
* Set persistence unit post processors
635
*/
636
public void setPersistenceUnitPostProcessors(
637
PersistenceUnitPostProcessor... postProcessors
638
) { }
639
640
/**
641
* Fluent builder for LocalContainerEntityManagerFactoryBean
642
*/
643
public static class Builder {
644
/**
645
* Set the managed types (entities) for this EntityManagerFactory
646
*/
647
public Builder managedTypes(PersistenceManagedTypes managedTypes) { }
648
649
/**
650
* Set packages to scan for entities
651
*/
652
public Builder packages(String... packagesToScan) { }
653
654
/**
655
* Set packages to scan using classes as package markers
656
*
657
* @param basePackageClasses Classes whose packages should be scanned
658
* @return Builder for fluent API
659
*/
660
public Builder packages(Class<?>... basePackageClasses) { }
661
662
/**
663
* Set persistence unit name
664
*/
665
public Builder persistenceUnit(String persistenceUnitName) { }
666
667
/**
668
* Set JPA properties
669
*/
670
public Builder properties(Map<String, ?> properties) { }
671
672
/**
673
* Set mapping resources (XML mappings)
674
*/
675
public Builder mappingResources(String... mappingResources) { }
676
677
/**
678
* Enable JTA transaction mode
679
*/
680
public Builder jta(boolean jta) { }
681
682
/**
683
* Build the LocalContainerEntityManagerFactoryBean
684
*/
685
public LocalContainerEntityManagerFactoryBean build() { }
686
}
687
}
688
```
689
690
**Usage Example - Multiple DataSources**:
691
692
```java
693
@Configuration
694
public class MultiDataSourceConfig {
695
696
@Bean
697
@Primary
698
@ConfigurationProperties(prefix = "spring.datasource.primary")
699
public DataSourceProperties primaryDataSourceProperties() {
700
return new DataSourceProperties();
701
}
702
703
@Bean
704
@Primary
705
public DataSource primaryDataSource() {
706
return primaryDataSourceProperties()
707
.initializeDataSourceBuilder()
708
.build();
709
}
710
711
@Bean
712
@Primary
713
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
714
EntityManagerFactoryBuilder builder,
715
@Qualifier("primaryDataSource") DataSource dataSource) {
716
return builder
717
.dataSource(dataSource)
718
.packages("com.example.primary.domain")
719
.persistenceUnit("primary")
720
.build();
721
}
722
723
@Bean
724
@ConfigurationProperties(prefix = "spring.datasource.secondary")
725
public DataSourceProperties secondaryDataSourceProperties() {
726
return new DataSourceProperties();
727
}
728
729
@Bean
730
public DataSource secondaryDataSource() {
731
return secondaryDataSourceProperties()
732
.initializeDataSourceBuilder()
733
.build();
734
}
735
736
@Bean
737
public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
738
EntityManagerFactoryBuilder builder,
739
@Qualifier("secondaryDataSource") DataSource dataSource) {
740
return builder
741
.dataSource(dataSource)
742
.packages("com.example.secondary.domain")
743
.persistenceUnit("secondary")
744
.build();
745
}
746
}
747
```
748
749
### Customization Interfaces
750
751
Customize Hibernate and EntityManagerFactory configuration through callback interfaces.
752
753
#### HibernatePropertiesCustomizer
754
755
```java { .api }
756
package org.springframework.boot.autoconfigure.orm.jpa;
757
758
@FunctionalInterface
759
public interface HibernatePropertiesCustomizer {
760
/**
761
* Customize Hibernate properties before EntityManagerFactory creation.
762
*
763
* @param hibernateProperties Map of Hibernate properties to customize
764
*/
765
void customize(Map<String, Object> hibernateProperties);
766
}
767
```
768
769
**Usage Example**:
770
771
```java
772
@Configuration
773
public class HibernateConfig {
774
775
@Bean
776
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer() {
777
return (hibernateProperties) -> {
778
// Enable Hibernate statistics
779
hibernateProperties.put("hibernate.generate_statistics", true);
780
781
// Configure second-level cache
782
hibernateProperties.put("hibernate.cache.use_second_level_cache", true);
783
hibernateProperties.put("hibernate.cache.region.factory_class",
784
"org.hibernate.cache.jcache.JCacheRegionFactory");
785
786
// Configure batch processing
787
hibernateProperties.put("hibernate.jdbc.batch_size", 25);
788
hibernateProperties.put("hibernate.order_inserts", true);
789
hibernateProperties.put("hibernate.order_updates", true);
790
};
791
}
792
}
793
```
794
795
#### EntityManagerFactoryBuilderCustomizer
796
797
```java { .api }
798
package org.springframework.boot.autoconfigure.orm.jpa;
799
800
@FunctionalInterface
801
public interface EntityManagerFactoryBuilderCustomizer {
802
/**
803
* Customize the EntityManagerFactoryBuilder before it's used.
804
*
805
* @param builder The EntityManagerFactoryBuilder to customize
806
*/
807
void customize(EntityManagerFactoryBuilder builder);
808
}
809
```
810
811
**Usage Example**:
812
813
```java
814
@Configuration
815
public class JpaConfig {
816
817
@Bean
818
public EntityManagerFactoryBuilderCustomizer entityManagerFactoryBuilderCustomizer() {
819
return (builder) -> {
820
// Configure async bootstrap for faster startup
821
builder.setBootstrapExecutor(asyncTaskExecutor());
822
823
// Add custom persistence unit post processors
824
builder.setPersistenceUnitPostProcessors(
825
new CustomPersistenceUnitPostProcessor()
826
);
827
};
828
}
829
830
@Bean
831
public AsyncTaskExecutor asyncTaskExecutor() {
832
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
833
executor.setCorePoolSize(2);
834
executor.setMaxPoolSize(2);
835
executor.setThreadNamePrefix("jpa-bootstrap-");
836
executor.initialize();
837
return executor;
838
}
839
}
840
```
841
842
### Initialization Order Control
843
844
Control EntityManagerFactory initialization order relative to other beans.
845
846
```java { .api }
847
package org.springframework.boot.autoconfigure.orm.jpa;
848
849
public class EntityManagerFactoryDependsOnPostProcessor
850
extends AbstractDependsOnBeanFactoryPostProcessor {
851
852
/**
853
* Make EntityManagerFactory depend on specific bean names.
854
*
855
* @param dependsOn Bean names that EntityManagerFactory should depend on
856
*/
857
public EntityManagerFactoryDependsOnPostProcessor(String... dependsOn) { }
858
859
/**
860
* Make EntityManagerFactory depend on beans of specific types.
861
*
862
* @param dependsOn Bean types that EntityManagerFactory should depend on
863
*/
864
public EntityManagerFactoryDependsOnPostProcessor(Class<?>... dependsOn) { }
865
}
866
```
867
868
**Usage Example**:
869
870
```java
871
@Configuration
872
public class InitializationOrderConfig {
873
874
/**
875
* Ensure EntityManagerFactory initializes after Flyway migrations
876
*/
877
@Bean
878
public static EntityManagerFactoryDependsOnPostProcessor
879
entityManagerFactoryDependsOnPostProcessor() {
880
return new EntityManagerFactoryDependsOnPostProcessor(Flyway.class);
881
}
882
}
883
```
884
885
### Naming Strategies
886
887
Customize how entity and column names are mapped to database table and column names.
888
889
```java { .api }
890
package org.springframework.boot.orm.jpa.hibernate;
891
892
import org.hibernate.boot.model.naming.Identifier;
893
import org.hibernate.boot.model.naming.ImplicitJoinTableNameSource;
894
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
895
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;
896
897
/**
898
* Spring's default implicit naming strategy.
899
* Join tables use format: {owning_table}_{property_name}
900
* Identical to ImplicitNamingStrategyJpaCompliantImpl except for join table naming.
901
*/
902
public class SpringImplicitNamingStrategy
903
extends ImplicitNamingStrategyJpaCompliantImpl {
904
905
/**
906
* Determine the implicit name for a join table.
907
* Uses format: {owning_physical_table_name}_{association_owning_property_name}
908
*
909
* @param source The source metadata for the join table
910
* @return The identifier for the join table name
911
*/
912
@Override
913
public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) { }
914
}
915
```
916
917
**Providing Custom Naming Strategy**:
918
919
```java
920
@Configuration
921
public class NamingStrategyConfig {
922
923
/**
924
* Override the default physical naming strategy
925
*/
926
@Bean
927
public PhysicalNamingStrategy physicalNamingStrategy() {
928
// Use standard JPA naming (no snake_case conversion)
929
return new PhysicalNamingStrategyStandardImpl();
930
}
931
932
/**
933
* Override the default implicit naming strategy
934
*/
935
@Bean
936
public ImplicitNamingStrategy implicitNamingStrategy() {
937
return new SpringImplicitNamingStrategy();
938
}
939
}
940
```
941
942
Or via properties:
943
944
```properties
945
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
946
spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
947
```
948
949
### Entity Scanning
950
951
Control which packages are scanned for JPA entities.
952
953
**Default Behavior**: Auto-scans main application package and sub-packages.
954
955
**Custom Scanning**:
956
957
```java
958
@Configuration
959
@EntityScan(basePackages = {
960
"com.example.domain",
961
"com.example.shared.entities"
962
})
963
public class EntityScanConfig {
964
}
965
```
966
967
**Entity Configuration**:
968
969
```java
970
@Entity
971
@Table(name = "products", indexes = {
972
@Index(name = "idx_product_sku", columnList = "sku"),
973
@Index(name = "idx_product_category", columnList = "category_id")
974
})
975
public class Product {
976
977
@Id
978
@GeneratedValue(strategy = GenerationType.IDENTITY)
979
private Long id;
980
981
@Column(unique = true, nullable = false, length = 50)
982
private String sku;
983
984
@Column(nullable = false)
985
private String name;
986
987
@Column(precision = 10, scale = 2)
988
private BigDecimal price;
989
990
@ManyToOne(fetch = FetchType.LAZY)
991
@JoinColumn(name = "category_id")
992
private Category category;
993
994
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
995
private List<Review> reviews = new ArrayList<>();
996
997
// Getters and setters
998
}
999
```
1000
1001
### Spring Data JPA Repositories
1002
1003
Create repository interfaces that Spring Data JPA automatically implements.
1004
1005
**Repository Interfaces**:
1006
1007
```java { .api }
1008
// CrudRepository - Basic CRUD operations
1009
public interface CrudRepository<T, ID> extends Repository<T, ID> {
1010
<S extends T> S save(S entity);
1011
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
1012
Optional<T> findById(ID id);
1013
boolean existsById(ID id);
1014
Iterable<T> findAll();
1015
Iterable<T> findAllById(Iterable<ID> ids);
1016
long count();
1017
void deleteById(ID id);
1018
void delete(T entity);
1019
void deleteAllById(Iterable<? extends ID> ids);
1020
void deleteAll(Iterable<? extends T> entities);
1021
void deleteAll();
1022
}
1023
1024
// JpaRepository - Adds JPA-specific methods
1025
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
1026
List<T> findAll();
1027
List<T> findAll(Sort sort);
1028
List<T> findAllById(Iterable<ID> ids);
1029
<S extends T> List<S> saveAll(Iterable<S> entities);
1030
void flush();
1031
<S extends T> S saveAndFlush(S entity);
1032
<S extends T> List<S> saveAllAndFlush(Iterable<S> entities);
1033
void deleteInBatch(Iterable<T> entities);
1034
void deleteAllInBatch(Iterable<T> entities);
1035
void deleteAllByIdInBatch(Iterable<ID> ids);
1036
void deleteAllInBatch();
1037
T getOne(ID id); // Deprecated, use getReferenceById
1038
T getReferenceById(ID id);
1039
}
1040
1041
// PagingAndSortingRepository - Pagination and sorting support
1042
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
1043
Iterable<T> findAll(Sort sort);
1044
Page<T> findAll(Pageable pageable);
1045
}
1046
```
1047
1048
**Query Methods**: Spring Data JPA derives queries from method names.
1049
1050
```java
1051
public interface UserRepository extends JpaRepository<User, Long> {
1052
// Derived query methods
1053
List<User> findByName(String name);
1054
List<User> findByNameAndEmail(String name, String email);
1055
List<User> findByNameOrEmail(String name, String email);
1056
List<User> findByAgeBetween(int minAge, int maxAge);
1057
List<User> findByNameContaining(String namePart);
1058
List<User> findByNameStartingWith(String prefix);
1059
List<User> findByNameIgnoreCase(String name);
1060
List<User> findByOrderByNameAsc();
1061
Optional<User> findFirstByEmail(String email);
1062
1063
// With pagination and sorting
1064
Page<User> findByName(String name, Pageable pageable);
1065
List<User> findByAge(int age, Sort sort);
1066
1067
// Count and exists queries
1068
long countByAge(int age);
1069
boolean existsByEmail(String email);
1070
1071
// Delete queries
1072
long deleteByAge(int age);
1073
void removeByName(String name);
1074
1075
// Custom JPQL queries
1076
@Query("SELECT u FROM User u WHERE u.age > :age")
1077
List<User> findUsersOlderThan(@Param("age") int age);
1078
1079
@Query("SELECT u FROM User u WHERE u.name LIKE %:namePart%")
1080
List<User> searchByName(@Param("namePart") String namePart);
1081
1082
// Native SQL queries
1083
@Query(value = "SELECT * FROM users WHERE email = ?1", nativeQuery = true)
1084
User findByEmailNative(String email);
1085
1086
// Modifying queries
1087
@Modifying
1088
@Query("UPDATE User u SET u.active = :active WHERE u.id = :id")
1089
int updateActiveStatus(@Param("id") Long id, @Param("active") boolean active);
1090
}
1091
```
1092
1093
**Pagination Example**:
1094
1095
```java
1096
@Service
1097
public class UserService {
1098
private final UserRepository userRepository;
1099
1100
public UserService(UserRepository userRepository) {
1101
this.userRepository = userRepository;
1102
}
1103
1104
public Page<User> getUsers(int page, int size) {
1105
Pageable pageable = PageRequest.of(page, size, Sort.by("name").ascending());
1106
return userRepository.findAll(pageable);
1107
}
1108
1109
public Page<User> searchUsers(String name, int page, int size) {
1110
Pageable pageable = PageRequest.of(page, size);
1111
return userRepository.findByName(name, pageable);
1112
}
1113
}
1114
```
1115
1116
### Transaction Management
1117
1118
JPA transactions are managed automatically through Spring's `@Transactional` annotation.
1119
1120
**Transaction Configuration**:
1121
1122
```java
1123
@Service
1124
public class OrderService {
1125
private final OrderRepository orderRepository;
1126
private final InventoryService inventoryService;
1127
1128
public OrderService(OrderRepository orderRepository,
1129
InventoryService inventoryService) {
1130
this.orderRepository = orderRepository;
1131
this.inventoryService = inventoryService;
1132
}
1133
1134
/**
1135
* Transactional method - changes committed or rolled back together
1136
*/
1137
@Transactional
1138
public Order createOrder(OrderRequest request) {
1139
// Check inventory
1140
inventoryService.reserveItems(request.getItems());
1141
1142
// Create order
1143
Order order = new Order();
1144
order.setCustomerId(request.getCustomerId());
1145
order.setItems(request.getItems());
1146
order.setStatus(OrderStatus.PENDING);
1147
1148
return orderRepository.save(order);
1149
// Transaction commits here if no exception thrown
1150
}
1151
1152
/**
1153
* Read-only transaction (optimization)
1154
*/
1155
@Transactional(readOnly = true)
1156
public Order getOrder(Long orderId) {
1157
return orderRepository.findById(orderId)
1158
.orElseThrow(() -> new OrderNotFoundException(orderId));
1159
}
1160
1161
/**
1162
* Custom transaction configuration
1163
*/
1164
@Transactional(
1165
propagation = Propagation.REQUIRES_NEW,
1166
isolation = Isolation.SERIALIZABLE,
1167
timeout = 30,
1168
rollbackFor = BusinessException.class
1169
)
1170
public void processRefund(Long orderId) {
1171
// Process refund in new transaction
1172
}
1173
}
1174
```
1175
1176
### JTA Integration
1177
1178
JTA platform automatically configured when JTA transaction manager is detected.
1179
1180
```java { .api }
1181
package org.springframework.boot.orm.jpa.hibernate;
1182
1183
import jakarta.transaction.TransactionManager;
1184
import jakarta.transaction.UserTransaction;
1185
import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;
1186
import org.springframework.transaction.jta.JtaTransactionManager;
1187
1188
/**
1189
* Hibernate JTA platform that integrates with Spring's JtaTransactionManager.
1190
* Automatically configured when JTA is detected.
1191
*/
1192
public class SpringJtaPlatform extends AbstractJtaPlatform {
1193
/**
1194
* Create JTA platform with Spring's transaction manager.
1195
*
1196
* @param transactionManager The JTA transaction manager
1197
*/
1198
public SpringJtaPlatform(JtaTransactionManager transactionManager) { }
1199
1200
/**
1201
* Locate the TransactionManager from the Spring JtaTransactionManager.
1202
*
1203
* @return The JTA TransactionManager
1204
*/
1205
@Override
1206
protected TransactionManager locateTransactionManager() { }
1207
1208
/**
1209
* Locate the UserTransaction from the Spring JtaTransactionManager.
1210
*
1211
* @return The JTA UserTransaction
1212
*/
1213
@Override
1214
protected UserTransaction locateUserTransaction() { }
1215
}
1216
```
1217
1218
## Types
1219
1220
```java { .api }
1221
// Database enum for spring.jpa.database property
1222
// Package: org.springframework.orm.jpa.vendor (Spring Framework)
1223
public enum Database {
1224
DEFAULT,
1225
DB2,
1226
DERBY,
1227
H2,
1228
HANA,
1229
HSQL,
1230
INFORMIX,
1231
MYSQL,
1232
ORACLE,
1233
POSTGRESQL,
1234
SQL_SERVER,
1235
SYBASE
1236
}
1237
1238
// Bootstrap mode for repository initialization
1239
// Package: org.springframework.data.repository.config (Spring Data Commons)
1240
public enum BootstrapMode {
1241
DEFAULT, // Eager initialization at startup
1242
DEFERRED, // Initialize when first accessed
1243
LAZY // Initialize on first actual use
1244
}
1245
1246
// Hibernate settings container (internal use)
1247
public class HibernateSettings {
1248
/**
1249
* Set the DDL auto supplier and return this instance for method chaining.
1250
*
1251
* @param ddlAuto Supplier for DDL auto mode
1252
* @return This HibernateSettings instance
1253
*/
1254
public HibernateSettings ddlAuto(Supplier<String> ddlAuto) { }
1255
1256
/**
1257
* Get the DDL auto mode.
1258
*
1259
* @return DDL auto mode or null if not set
1260
*/
1261
public String getDdlAuto() { }
1262
1263
/**
1264
* Set the Hibernate properties customizers and return this instance for method chaining.
1265
*
1266
* @param customizers Collection of customizers to apply
1267
* @return This HibernateSettings instance
1268
*/
1269
public HibernateSettings hibernatePropertiesCustomizers(
1270
Collection<HibernatePropertiesCustomizer> customizers
1271
) { }
1272
1273
/**
1274
* Get the Hibernate properties customizers.
1275
*
1276
* @return Collection of customizers
1277
*/
1278
public Collection<HibernatePropertiesCustomizer> getHibernatePropertiesCustomizers() { }
1279
}
1280
```
1281
1282
## Dependencies
1283
1284
This starter aggregates the following dependencies:
1285
1286
- `spring-boot-starter` - Core Spring Boot functionality
1287
- `spring-boot-starter-jdbc` - JDBC and DataSource support
1288
- `hibernate-core` (org.hibernate.orm) - Hibernate ORM implementation
1289
- `spring-data-jpa` (org.springframework.data) - Spring Data JPA repositories
1290
- `spring-aspects` (org.springframework) - AOP support for @Transactional
1291
1292
## Common Patterns
1293
1294
### Testing with @DataJpaTest
1295
1296
```java
1297
@DataJpaTest
1298
class UserRepositoryTest {
1299
1300
@Autowired
1301
private UserRepository userRepository;
1302
1303
@Autowired
1304
private TestEntityManager entityManager;
1305
1306
@Test
1307
void testFindByName() {
1308
// Given
1309
User user = new User();
1310
user.setName("Alice");
1311
user.setEmail("alice@example.com");
1312
entityManager.persist(user);
1313
entityManager.flush();
1314
1315
// When
1316
List<User> users = userRepository.findByName("Alice");
1317
1318
// Then
1319
assertThat(users).hasSize(1);
1320
assertThat(users.get(0).getEmail()).isEqualTo("alice@example.com");
1321
}
1322
}
1323
```
1324
1325
### Auditing
1326
1327
Enable automatic auditing of created/modified dates and users:
1328
1329
```java
1330
@Configuration
1331
@EnableJpaAuditing
1332
public class JpaAuditingConfig {
1333
1334
@Bean
1335
public AuditorAware<String> auditorProvider() {
1336
// Return current user from security context
1337
return () -> Optional.of(
1338
SecurityContextHolder.getContext()
1339
.getAuthentication()
1340
.getName()
1341
);
1342
}
1343
}
1344
1345
@Entity
1346
@EntityListeners(AuditingEntityListener.class)
1347
public class AuditableEntity {
1348
1349
@CreatedDate
1350
@Column(nullable = false, updatable = false)
1351
private Instant createdDate;
1352
1353
@LastModifiedDate
1354
private Instant lastModifiedDate;
1355
1356
@CreatedBy
1357
@Column(nullable = false, updatable = false)
1358
private String createdBy;
1359
1360
@LastModifiedBy
1361
private String lastModifiedBy;
1362
}
1363
```
1364
1365
### Specifications (Dynamic Queries)
1366
1367
```java
1368
public interface UserRepository extends JpaRepository<User, Long>,
1369
JpaSpecificationExecutor<User> {
1370
}
1371
1372
public class UserSpecifications {
1373
1374
public static Specification<User> hasName(String name) {
1375
return (root, query, cb) ->
1376
name == null ? null : cb.equal(root.get("name"), name);
1377
}
1378
1379
public static Specification<User> isActive() {
1380
return (root, query, cb) -> cb.isTrue(root.get("active"));
1381
}
1382
1383
public static Specification<User> ageGreaterThan(int age) {
1384
return (root, query, cb) -> cb.greaterThan(root.get("age"), age);
1385
}
1386
}
1387
1388
// Usage
1389
@Service
1390
public class UserSearchService {
1391
private final UserRepository userRepository;
1392
1393
public List<User> searchUsers(String name, Integer minAge, Boolean active) {
1394
Specification<User> spec = Specification.where(null);
1395
1396
if (name != null) {
1397
spec = spec.and(UserSpecifications.hasName(name));
1398
}
1399
if (minAge != null) {
1400
spec = spec.and(UserSpecifications.ageGreaterThan(minAge));
1401
}
1402
if (Boolean.TRUE.equals(active)) {
1403
spec = spec.and(UserSpecifications.isActive());
1404
}
1405
1406
return userRepository.findAll(spec);
1407
}
1408
}
1409
```
1410