0
# Persistence Context Management
1
2
Spring ORM provides advanced persistence context management through annotation-driven dependency injection, container-managed and application-managed persistence contexts, persistence unit configuration, and comprehensive lifecycle management. This enables proper resource management and integration with Spring's dependency injection container.
3
4
## Capabilities
5
6
### Persistence Annotation Processing
7
8
Automatic processing of JPA annotations for dependency injection of EntityManager and EntityManagerFactory instances with proper lifecycle management.
9
10
```java { .api }
11
public class PersistenceAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor,
12
DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware, Serializable {
13
public void setDefaultPersistenceUnitName(String unitName);
14
public void setPersistenceUnits(Map<String, PersistenceUnitInfo> persistenceUnits);
15
public void setPersistenceContexts(Map<String, EntityManagerFactory> persistenceContexts);
16
public void setJndiEnvironment(Properties jndiEnvironment);
17
public void setResourceRef(boolean resourceRef);
18
19
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException;
20
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
21
public Object postProcessBeforeInstantiation(Class<?> beanType, String beanName) throws BeansException;
22
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
23
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
24
}
25
26
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
27
@Retention(RetentionPolicy.RUNTIME)
28
public @interface PersistenceContext {
29
String name() default "";
30
String unitName() default "";
31
PersistenceContextType type() default PersistenceContextType.TRANSACTION;
32
SynchronizationType synchronization() default SynchronizationType.SYNCHRONIZED;
33
PersistenceProperty[] properties() default {};
34
}
35
36
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
37
@Retention(RetentionPolicy.RUNTIME)
38
public @interface PersistenceUnit {
39
String name() default "";
40
String unitName() default "";
41
}
42
43
public enum PersistenceContextType {
44
TRANSACTION,
45
EXTENDED
46
}
47
48
public enum SynchronizationType {
49
SYNCHRONIZED,
50
UNSYNCHRONIZED
51
}
52
```
53
54
#### Usage Example
55
56
```java
57
@Configuration
58
@EnableJpaRepositories
59
public class PersistenceConfig {
60
61
@Bean
62
public PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() {
63
PersistenceAnnotationBeanPostProcessor processor = new PersistenceAnnotationBeanPostProcessor();
64
65
// Set default persistence unit name
66
processor.setDefaultPersistenceUnitName("primaryPU");
67
68
// Configure specific persistence units
69
Map<String, PersistenceUnitInfo> persistenceUnits = new HashMap<>();
70
persistenceUnits.put("primaryPU", primaryPersistenceUnitInfo());
71
persistenceUnits.put("secondaryPU", secondaryPersistenceUnitInfo());
72
processor.setPersistenceUnits(persistenceUnits);
73
74
// Configure EntityManagerFactory mappings
75
Map<String, EntityManagerFactory> persistenceContexts = new HashMap<>();
76
persistenceContexts.put("primaryPU", primaryEntityManagerFactory());
77
persistenceContexts.put("secondaryPU", secondaryEntityManagerFactory());
78
processor.setPersistenceContexts(persistenceContexts);
79
80
return processor;
81
}
82
}
83
84
@Repository
85
public class UserRepository {
86
87
// Inject default EntityManager
88
@PersistenceContext
89
private EntityManager entityManager;
90
91
// Inject EntityManager for specific persistence unit
92
@PersistenceContext(unitName = "primaryPU")
93
private EntityManager primaryEntityManager;
94
95
// Inject EntityManager with extended persistence context
96
@PersistenceContext(
97
unitName = "primaryPU",
98
type = PersistenceContextType.EXTENDED,
99
properties = {
100
@PersistenceProperty(name = "hibernate.cache.use_second_level_cache", value = "true"),
101
@PersistenceProperty(name = "hibernate.cache.region.factory_class",
102
value = "org.hibernate.cache.jcache.JCacheRegionFactory")
103
}
104
)
105
private EntityManager extendedEntityManager;
106
107
// Inject EntityManagerFactory
108
@PersistenceUnit(unitName = "primaryPU")
109
private EntityManagerFactory entityManagerFactory;
110
111
@Transactional
112
public void saveUser(User user) {
113
entityManager.persist(user);
114
}
115
116
@Transactional(readOnly = true)
117
public User findUserById(Long id) {
118
return entityManager.find(User.class, id);
119
}
120
121
// Using EntityManagerFactory for programmatic EntityManager creation
122
public void performBatchOperation(List<User> users) {
123
EntityManager em = entityManagerFactory.createEntityManager();
124
EntityTransaction tx = em.getTransaction();
125
126
try {
127
tx.begin();
128
129
for (int i = 0; i < users.size(); i++) {
130
em.persist(users.get(i));
131
132
if (i % 50 == 0) {
133
em.flush();
134
em.clear();
135
}
136
}
137
138
tx.commit();
139
} catch (Exception ex) {
140
if (tx.isActive()) {
141
tx.rollback();
142
}
143
throw ex;
144
} finally {
145
em.close();
146
}
147
}
148
}
149
```
150
151
### Persistence Unit Management
152
153
Comprehensive management of JPA persistence units including configuration, managed types discovery, and persistence.xml processing.
154
155
```java { .api }
156
public interface PersistenceUnitManager {
157
PersistenceUnitInfo obtainDefaultPersistenceUnitInfo() throws IllegalArgumentException;
158
PersistenceUnitInfo obtainPersistenceUnitInfo(String persistenceUnitName) throws IllegalArgumentException, IllegalStateException;
159
}
160
161
public class DefaultPersistenceUnitManager implements PersistenceUnitManager, ResourceLoaderAware, DisposableBean {
162
public static final String DEFAULT_PERSISTENCE_XML_LOCATION = "classpath*:META-INF/persistence.xml";
163
public static final String ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION = "classpath:";
164
public static final String ORIGINAL_DEFAULT_PERSISTENCE_UNIT_NAME = "default";
165
166
public void setPersistenceXmlLocations(String... persistenceXmlLocations);
167
public void setDefaultPersistenceUnitRootLocation(String defaultPersistenceUnitRootLocation);
168
public void setDefaultPersistenceUnitName(String defaultPersistenceUnitName);
169
public void setPackagesToScan(String... packagesToScan);
170
public void setManagedTypes(PersistenceManagedTypes managedTypes);
171
public void setManagedClassNameFilter(ManagedClassNameFilter managedClassNameFilter);
172
public void setMappingResources(String... mappingResources);
173
public void setJtaDataSource(DataSource jtaDataSource);
174
public void setDataSource(DataSource dataSource);
175
public void setPersistenceUnitPostProcessors(PersistenceUnitPostProcessor... persistenceUnitPostProcessors);
176
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver);
177
178
public PersistenceUnitInfo obtainDefaultPersistenceUnitInfo() throws IllegalArgumentException;
179
public PersistenceUnitInfo obtainPersistenceUnitInfo(String persistenceUnitName) throws IllegalArgumentException, IllegalStateException;
180
}
181
182
public interface PersistenceUnitPostProcessor {
183
void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui);
184
}
185
186
public interface ManagedClassNameFilter {
187
boolean matches(String className);
188
}
189
```
190
191
#### Usage Example
192
193
```java
194
@Configuration
195
public class PersistenceUnitConfig {
196
197
@Bean
198
public PersistenceUnitManager persistenceUnitManager() {
199
DefaultPersistenceUnitManager manager = new DefaultPersistenceUnitManager();
200
201
// Set persistence.xml locations
202
manager.setPersistenceXmlLocations(
203
"classpath:META-INF/persistence.xml",
204
"classpath:META-INF/test-persistence.xml"
205
);
206
207
// Configure default settings
208
manager.setDefaultPersistenceUnitRootLocation("classpath:");
209
manager.setDefaultPersistenceUnitName("primaryPU");
210
211
// Set packages to scan for entities
212
manager.setPackagesToScan(
213
"com.example.entity",
214
"com.example.model",
215
"com.example.domain"
216
);
217
218
// Configure managed types filter
219
manager.setManagedClassNameFilter(className ->
220
className.startsWith("com.example") &&
221
!className.contains("Test")
222
);
223
224
// Set mapping resources
225
manager.setMappingResources(
226
"META-INF/orm.xml",
227
"META-INF/queries.xml"
228
);
229
230
// Configure data sources
231
manager.setDataSource(primaryDataSource());
232
manager.setJtaDataSource(jtaDataSource());
233
234
// Add post-processors
235
manager.setPersistenceUnitPostProcessors(
236
new CustomPersistenceUnitPostProcessor(),
237
new AuditingPersistenceUnitPostProcessor()
238
);
239
240
return manager;
241
}
242
243
@Bean
244
public DataSource primaryDataSource() {
245
HikariDataSource dataSource = new HikariDataSource();
246
dataSource.setJdbcUrl("jdbc:postgresql://localhost:5432/primary");
247
dataSource.setUsername("user");
248
dataSource.setPassword("password");
249
return dataSource;
250
}
251
}
252
253
// Custom post-processor for persistence unit customization
254
public class CustomPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
255
256
@Override
257
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
258
// Add custom properties
259
pui.getProperties().setProperty("hibernate.show_sql", "true");
260
pui.getProperties().setProperty("hibernate.format_sql", "true");
261
pui.getProperties().setProperty("hibernate.use_sql_comments", "true");
262
263
// Add additional managed classes programmatically
264
pui.addManagedClassName("com.example.entity.DynamicEntity");
265
266
// Add mapping files
267
pui.addMappingFileName("META-INF/custom-mappings.xml");
268
269
// Customize transaction type based on environment
270
if (isProductionEnvironment()) {
271
pui.setTransactionType(PersistenceUnitTransactionType.JTA);
272
} else {
273
pui.setTransactionType(PersistenceUnitTransactionType.RESOURCE_LOCAL);
274
}
275
}
276
}
277
```
278
279
### Managed Types Discovery
280
281
Support for discovering and configuring managed entity types, embeddables, and mapped superclasses for JPA persistence units.
282
283
```java { .api }
284
public interface PersistenceManagedTypes {
285
Set<String> getManagedClassNames();
286
Set<String> getManagedPackages();
287
288
static PersistenceManagedTypes of(String... managedClassNames);
289
static PersistenceManagedTypes of(Class<?>... managedClasses);
290
static PersistenceManagedTypes empty();
291
static PersistenceManagedTypes fromIterable(Iterable<String> managedClassNames);
292
}
293
294
public class SimplePersistenceManagedTypes implements PersistenceManagedTypes {
295
public SimplePersistenceManagedTypes(Collection<String> managedClassNames, Collection<String> managedPackages);
296
297
public Set<String> getManagedClassNames();
298
public Set<String> getManagedPackages();
299
}
300
301
public class MutablePersistenceUnitInfo implements SmartPersistenceUnitInfo {
302
public void setPersistenceUnitName(String persistenceUnitName);
303
public void setPersistenceProviderClassName(String persistenceProviderClassName);
304
public void setTransactionType(PersistenceUnitTransactionType transactionType);
305
public void setJtaDataSource(DataSource jtaDataSource);
306
public void setNonJtaDataSource(DataSource nonJtaDataSource);
307
public void addManagedClassName(String managedClassName);
308
public void addMappingFileName(String mappingFileName);
309
public void addJarFileUrl(URL jarFileUrl);
310
public void setPersistenceUnitRootUrl(URL persistenceUnitRootUrl);
311
public void setExcludeUnlistedClasses(boolean excludeUnlistedClasses);
312
public void setSharedCacheMode(SharedCacheMode sharedCacheMode);
313
public void setValidationMode(ValidationMode validationMode);
314
public void addProperty(String name, Object value);
315
public void setProperties(Properties properties);
316
public void setClassLoader(ClassLoader classLoader);
317
}
318
```
319
320
#### Usage Example
321
322
```java
323
@Configuration
324
public class ManagedTypesConfig {
325
326
@Bean
327
public PersistenceManagedTypes primaryManagedTypes() {
328
// Static managed types
329
return PersistenceManagedTypes.of(
330
User.class,
331
Product.class,
332
Order.class,
333
OrderItem.class,
334
Customer.class
335
);
336
}
337
338
@Bean
339
public PersistenceManagedTypes dynamicManagedTypes() {
340
// Dynamic managed types discovery
341
Set<String> managedClassNames = new HashSet<>();
342
Set<String> managedPackages = new HashSet<>();
343
344
// Scan packages for entities
345
scanPackageForEntities("com.example.entity", managedClassNames);
346
scanPackageForEntities("com.example.model", managedClassNames);
347
348
// Add packages for automatic scanning
349
managedPackages.add("com.example.embeddable");
350
managedPackages.add("com.example.converter");
351
352
return new SimplePersistenceManagedTypes(managedClassNames, managedPackages);
353
}
354
355
@Bean
356
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
357
PersistenceManagedTypes managedTypes) {
358
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
359
em.setDataSource(dataSource());
360
em.setManagedTypes(managedTypes);
361
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
362
return em;
363
}
364
365
private void scanPackageForEntities(String packageName, Set<String> managedClassNames) {
366
// Implementation would use reflection or classpath scanning
367
// to discover @Entity, @Embeddable, @MappedSuperclass annotations
368
ClassPathScanningCandidateComponentProvider scanner =
369
new ClassPathScanningCandidateComponentProvider(false);
370
371
scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
372
scanner.addIncludeFilter(new AnnotationTypeFilter(Embeddable.class));
373
scanner.addIncludeFilter(new AnnotationTypeFilter(MappedSuperclass.class));
374
375
for (BeanDefinition bd : scanner.findCandidateComponents(packageName)) {
376
managedClassNames.add(bd.getBeanClassName());
377
}
378
}
379
}
380
381
// Custom managed types implementation with filtering
382
public class FilteredPersistenceManagedTypes implements PersistenceManagedTypes {
383
384
private final Set<String> managedClassNames;
385
private final Set<String> managedPackages;
386
private final Predicate<String> classFilter;
387
388
public FilteredPersistenceManagedTypes(
389
Set<String> managedClassNames,
390
Set<String> managedPackages,
391
Predicate<String> classFilter) {
392
this.managedClassNames = managedClassNames;
393
this.managedPackages = managedPackages;
394
this.classFilter = classFilter;
395
}
396
397
@Override
398
public Set<String> getManagedClassNames() {
399
return managedClassNames.stream()
400
.filter(classFilter)
401
.collect(Collectors.toSet());
402
}
403
404
@Override
405
public Set<String> getManagedPackages() {
406
return managedPackages;
407
}
408
}
409
```
410
411
### Extended EntityManager Support
412
413
Support for creating extended EntityManager instances that span multiple transactions and provide application-managed persistence contexts.
414
415
```java { .api }
416
public abstract class ExtendedEntityManagerCreator {
417
public static EntityManager createApplicationManagedEntityManager(EntityManager rawEntityManager, EntityManagerFactoryInfo emfInfo);
418
public static EntityManager createContainerManagedEntityManager(EntityManagerFactory emf, Map<?, ?> properties, boolean synchronizedWithTransaction);
419
}
420
421
public class SharedEntityManagerBean extends EntityManagerFactoryAccessor
422
implements FactoryBean<EntityManager>, InitializingBean {
423
public void setPersistenceUnitName(String persistenceUnitName);
424
public void setJpaProperties(Properties jpaProperties);
425
public void setEntityManagerInterface(Class<? extends EntityManager> entityManagerInterface);
426
public void setSynchronizedWithTransaction(boolean synchronizedWithTransaction);
427
428
public EntityManager getObject();
429
public Class<? extends EntityManager> getObjectType();
430
public boolean isSingleton();
431
}
432
433
public interface EntityManagerProxy extends EntityManager {
434
EntityManager getTargetEntityManager();
435
}
436
```
437
438
#### Usage Example
439
440
```java
441
@Configuration
442
public class ExtendedEntityManagerConfig {
443
444
@Bean
445
public EntityManager applicationManagedEntityManager(
446
EntityManagerFactory entityManagerFactory) {
447
// Create application-managed EntityManager
448
EntityManager rawEntityManager = entityManagerFactory.createEntityManager();
449
EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) entityManagerFactory;
450
451
return ExtendedEntityManagerCreator.createApplicationManagedEntityManager(
452
rawEntityManager,
453
emfInfo
454
);
455
}
456
457
@Bean
458
public EntityManager containerManagedEntityManager(
459
EntityManagerFactory entityManagerFactory) {
460
// Create container-managed EntityManager with custom properties
461
Map<String, Object> properties = new HashMap<>();
462
properties.put("hibernate.jdbc.fetch_size", 50);
463
properties.put("hibernate.jdbc.batch_size", 25);
464
465
return ExtendedEntityManagerCreator.createContainerManagedEntityManager(
466
entityManagerFactory,
467
properties,
468
true // synchronized with transaction
469
);
470
}
471
472
@Bean
473
public SharedEntityManagerBean sharedEntityManager() {
474
SharedEntityManagerBean bean = new SharedEntityManagerBean();
475
bean.setPersistenceUnitName("primaryPU");
476
477
// Custom JPA properties
478
Properties jpaProperties = new Properties();
479
jpaProperties.setProperty("hibernate.cache.use_query_cache", "true");
480
jpaProperties.setProperty("hibernate.cache.use_second_level_cache", "true");
481
bean.setJpaProperties(jpaProperties);
482
483
// Specify EntityManager interface (for proxy creation)
484
bean.setEntityManagerInterface(EntityManager.class);
485
486
// Configure transaction synchronization
487
bean.setSynchronizedWithTransaction(false);
488
489
return bean;
490
}
491
}
492
493
@Service
494
public class ExtendedPersistenceService {
495
496
// Application-managed EntityManager (spans multiple transactions)
497
@Autowired
498
@Qualifier("applicationManagedEntityManager")
499
private EntityManager applicationEntityManager;
500
501
// Container-managed EntityManager (transaction-scoped)
502
@Autowired
503
@Qualifier("containerManagedEntityManager")
504
private EntityManager containerEntityManager;
505
506
// Shared EntityManager (thread-safe proxy)
507
@Autowired
508
@Qualifier("sharedEntityManager")
509
private EntityManager sharedEntityManager;
510
511
// Extended persistence context for complex operations
512
public void performExtendedOperation(List<Long> userIds) {
513
try {
514
applicationEntityManager.getTransaction().begin();
515
516
// Load entities in extended context
517
List<User> users = new ArrayList<>();
518
for (Long id : userIds) {
519
User user = applicationEntityManager.find(User.class, id);
520
if (user != null) {
521
users.add(user);
522
}
523
}
524
525
// Perform complex modifications
526
for (User user : users) {
527
// Entities remain managed across method calls
528
processUser(user);
529
updateUserProfile(user);
530
addUserActivity(user);
531
}
532
533
applicationEntityManager.getTransaction().commit();
534
535
} catch (Exception ex) {
536
if (applicationEntityManager.getTransaction().isActive()) {
537
applicationEntityManager.getTransaction().rollback();
538
}
539
throw ex;
540
}
541
}
542
543
@Transactional
544
public void performContainerManagedOperation(User user) {
545
// Uses container-managed EntityManager (transaction-scoped)
546
containerEntityManager.persist(user);
547
548
// EntityManager is automatically managed by Spring transaction
549
}
550
551
public void performNonTransactionalQuery() {
552
// Shared EntityManager can be used outside transactions for read operations
553
List<User> users = sharedEntityManager
554
.createQuery("SELECT u FROM User u WHERE u.active = true", User.class)
555
.getResultList();
556
557
// Process users...
558
}
559
560
// Check if EntityManager is a proxy
561
public void inspectEntityManager() {
562
if (sharedEntityManager instanceof EntityManagerProxy) {
563
EntityManagerProxy proxy = (EntityManagerProxy) sharedEntityManager;
564
EntityManager target = proxy.getTargetEntityManager();
565
566
log.info("Using EntityManager proxy, target: {}", target.getClass().getName());
567
}
568
}
569
}
570
```
571
572
### Persistence Context Integration with Web Layer
573
574
Integration patterns for managing persistence contexts in web applications, including request-scoped EntityManager and lazy loading support.
575
576
```java { .api }
577
public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
578
public static final String DEFAULT_ENTITY_MANAGER_FACTORY_BEAN_NAME = "entityManagerFactory";
579
580
public void setEntityManagerFactoryBeanName(String entityManagerFactoryBeanName);
581
public String getEntityManagerFactoryBeanName();
582
public void setPersistenceUnitName(String persistenceUnitName);
583
}
584
585
public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAccessor
586
implements AsyncWebRequestInterceptor {
587
public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
588
589
public void preHandle(WebRequest request) throws DataAccessException;
590
public void postHandle(WebRequest request, ModelMap model);
591
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException;
592
public void afterConcurrentHandlingStarted(WebRequest request);
593
}
594
```
595
596
#### Usage Example
597
598
```java
599
@Configuration
600
@EnableWebMvc
601
public class WebPersistenceConfig implements WebMvcConfigurer {
602
603
@Autowired
604
private EntityManagerFactory entityManagerFactory;
605
606
@Override
607
public void addInterceptors(InterceptorRegistry registry) {
608
OpenEntityManagerInViewInterceptor interceptor = new OpenEntityManagerInViewInterceptor();
609
interceptor.setEntityManagerFactory(entityManagerFactory);
610
611
registry.addWebRequestInterceptor(interceptor)
612
.addPathPatterns("/api/**") // Apply to specific paths
613
.excludePathPatterns("/api/health", "/api/metrics"); // Exclude certain paths
614
}
615
}
616
617
// Alternative: Using Filter approach
618
@WebFilter(urlPatterns = "/app/*")
619
public class CustomOpenEntityManagerInViewFilter extends OpenEntityManagerInViewFilter {
620
621
@Override
622
public void initFilterBean() {
623
setEntityManagerFactoryBeanName("primaryEntityManagerFactory");
624
setPersistenceUnitName("primaryPU");
625
}
626
627
@Override
628
protected boolean shouldNotFilterErrorDispatch() {
629
return false; // Include error dispatches
630
}
631
632
@Override
633
protected boolean shouldNotFilterAsyncDispatch() {
634
return false; // Include async dispatches
635
}
636
}
637
638
@RestController
639
@RequestMapping("/api/users")
640
public class UserController {
641
642
@PersistenceContext
643
private EntityManager entityManager;
644
645
@GetMapping("/{id}")
646
public UserDto getUser(@PathVariable Long id) {
647
// EntityManager is available throughout the request
648
User user = entityManager.find(User.class, id);
649
650
if (user != null) {
651
// Lazy associations can be accessed due to open EntityManager
652
user.getOrders().size(); // Triggers lazy loading
653
user.getProfile().getPreferences().size(); // Deep lazy loading
654
655
return convertToDto(user);
656
}
657
658
throw new EntityNotFoundException("User not found: " + id);
659
}
660
661
@GetMapping("/{id}/orders")
662
public List<OrderDto> getUserOrders(@PathVariable Long id) {
663
// Complex query with lazy loading support
664
User user = entityManager.find(User.class, id);
665
if (user != null) {
666
return user.getOrders().stream()
667
.map(this::convertOrderToDto)
668
.collect(Collectors.toList());
669
}
670
return Collections.emptyList();
671
}
672
}
673
674
// Async handling with persistence context
675
@RestController
676
@RequestMapping("/api/async")
677
public class AsyncController {
678
679
@PersistenceContext
680
private EntityManager entityManager;
681
682
@GetMapping("/users/{id}")
683
public CompletableFuture<UserDto> getUserAsync(@PathVariable Long id) {
684
// EntityManager is properly managed in async context
685
return CompletableFuture.supplyAsync(() -> {
686
User user = entityManager.find(User.class, id);
687
return convertToDto(user);
688
});
689
}
690
}
691
```
692
693
## Types
694
695
```java { .api }
696
import jakarta.persistence.EntityManager;
697
import jakarta.persistence.EntityManagerFactory;
698
import jakarta.persistence.EntityTransaction;
699
import jakarta.persistence.PersistenceContext;
700
import jakarta.persistence.PersistenceUnit;
701
import jakarta.persistence.PersistenceContextType;
702
import jakarta.persistence.PersistenceProperty;
703
import jakarta.persistence.SynchronizationType;
704
import jakarta.persistence.spi.PersistenceUnitInfo;
705
import jakarta.persistence.spi.PersistenceUnitTransactionType;
706
import jakarta.persistence.SharedCacheMode;
707
import jakarta.persistence.ValidationMode;
708
import org.springframework.beans.factory.config.BeanPostProcessor;
709
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
710
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
711
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
712
import org.springframework.core.PriorityOrdered;
713
import org.springframework.beans.factory.BeanFactoryAware;
714
import org.springframework.web.context.request.WebRequest;
715
import org.springframework.ui.ModelMap;
716
import javax.sql.DataSource;
717
import java.net.URL;
718
import java.util.Map;
719
import java.util.Set;
720
import java.util.Properties;
721
import java.util.Collection;
722
import java.util.function.Predicate;
723
```