Utilities for creating shared, thread-bound EntityManager and Session proxies that integrate with Spring transaction management.
Prefer @PersistenceContext injection (automatic):
@Service
public class UserService {
@PersistenceContext // Automatically creates shared proxy
private EntityManager entityManager;
@Transactional
public void saveUser(User user) {
entityManager.persist(user);
// No need to close - managed by Spring
}
}Use explicit creation only for advanced scenarios (documented below).
@Configuration
public class JpaConfig {
@Bean
public EntityManager sharedEntityManager(EntityManagerFactory emf) {
return SharedEntityManagerCreator.createSharedEntityManager(emf);
}
}
@Service
public class UserService {
private final EntityManager entityManager;
public UserService(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Transactional(readOnly = true)
public User findUser(Long id) {
return entityManager.find(User.class, id);
}
}@Bean
public EntityManager sharedEntityManager(EntityManagerFactory emf) {
Map<String, Object> properties = new HashMap<>();
properties.put("jakarta.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
properties.put("jakarta.persistence.cache.storeMode", CacheStoreMode.REFRESH);
return SharedEntityManagerCreator.createSharedEntityManager(emf, properties);
}@Bean
public EntityManager sharedEntityManager(EntityManagerFactory emf) {
Map<String, Object> properties = new HashMap<>();
boolean synchronizedWithTransaction = true;
return SharedEntityManagerCreator.createSharedEntityManager(
emf, properties, synchronizedWithTransaction);
}@Configuration
public class HibernateConfig {
@Bean
public Session sharedSession(SessionFactory sessionFactory) {
return SharedSessionCreator.createSharedSession(sessionFactory);
}
}
@Service
public class ProductService {
private final Session session;
public ProductService(Session session) {
this.session = session;
}
@Transactional(readOnly = true)
public Product findProduct(Long id) {
return session.get(Product.class, id);
}
}@Bean
public Session sharedSession(SessionFactory sessionFactory) {
SessionBuilder sessionBuilder = sessionFactory.withOptions()
.tenantIdentifier("tenant-123")
.eventListeners(new CustomInterceptor());
return SharedSessionCreator.createSharedSession(sessionFactory, sessionBuilder);
}For application-managed or container-managed extended EntityManagers:
@Configuration
public class JpaConfig {
@Bean
@Scope("request")
public EntityManager extendedEntityManager(EntityManagerFactory emf) {
// Create container-managed extended EntityManager
return ExtendedEntityManagerCreator.createContainerManagedEntityManager(emf);
}
}
@Controller
@Scope("request")
public class ConversationController {
private final EntityManager extendedEntityManager;
public ConversationController(EntityManager extendedEntityManager) {
this.extendedEntityManager = extendedEntityManager;
}
// EntityManager persists across multiple method calls
// within the same request scope
}@Service
@Transactional
public class OrderService {
// Shared EntityManager - same instance injected everywhere
private final EntityManager entityManager;
private final ProductService productService;
public OrderService(EntityManager entityManager, ProductService productService) {
this.entityManager = entityManager;
this.productService = productService;
}
public Order createOrder(Long productId, int quantity) {
// Get product from ProductService (uses same shared EntityManager)
Product product = productService.findProduct(productId);
// Create order using same EntityManager instance
Order order = new Order();
order.setProduct(product);
order.setQuantity(quantity);
entityManager.persist(order);
return order;
}
}
@Service
@Transactional(readOnly = true)
public class ProductService {
// Same shared EntityManager instance
private final EntityManager entityManager;
public ProductService(EntityManager entityManager) {
this.entityManager = entityManager;
}
public Product findProduct(Long id) {
return entityManager.find(Product.class, id);
}
}@Service
public class UserService {
@Autowired // or @PersistenceContext
private EntityManager entityManager; // Shared proxy
@Transactional
public void saveUser(User user) {
entityManager.persist(user);
// No need to close - managed by Spring
}
}@Service
public class UserService {
@PersistenceUnit
private EntityManagerFactory emf;
public void saveUser(User user) {
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
em.persist(user);
em.getTransaction().commit();
} finally {
em.close(); // Must manually close
}
}
}The shared approach simplifies code, integrates with Spring's transaction management, and reduces boilerplate.
abstract class SharedEntityManagerCreator {
// Basic creation
static EntityManager createSharedEntityManager(EntityManagerFactory emf);
// With properties
static EntityManager createSharedEntityManager(
EntityManagerFactory emf,
Map<?, ?> properties
);
// With transaction synchronization control
static EntityManager createSharedEntityManager(
EntityManagerFactory emf,
Map<?, ?> properties,
boolean synchronizedWithTransaction
);
// With custom EntityManager interfaces
static EntityManager createSharedEntityManager(
EntityManagerFactory emf,
Map<?, ?> properties,
Class<?>... entityManagerInterfaces
);
// Full configuration
static EntityManager createSharedEntityManager(
EntityManagerFactory emf,
Map<?, ?> properties,
boolean synchronizedWithTransaction,
Class<?>... entityManagerInterfaces
);
}abstract class SharedSessionCreator {
// Basic creation
static Session createSharedSession(SessionFactory sessionFactory);
// With SessionBuilder
static Session createSharedSession(
SessionFactory sessionFactory,
SessionBuilder sessionBuilder
);
}abstract class ExtendedEntityManagerCreator {
// Application-managed extended EntityManager
static EntityManager createApplicationManagedEntityManager(
EntityManager rawEntityManager,
EntityManagerFactoryInfo emfInfo
);
static EntityManager createApplicationManagedEntityManager(
EntityManager rawEntityManager,
EntityManagerFactoryInfo emfInfo,
boolean synchronizedWithTransaction
);
// Container-managed extended EntityManager
static EntityManager createContainerManagedEntityManager(
EntityManager rawEntityManager,
EntityManagerFactoryInfo emfInfo
);
static EntityManager createContainerManagedEntityManager(EntityManagerFactory emf);
static EntityManager createContainerManagedEntityManager(
EntityManagerFactory emf,
Map<?, ?> properties
);
static EntityManager createContainerManagedEntityManager(
EntityManagerFactory emf,
Map<?, ?> properties,
boolean synchronizedWithTransaction
);
}