When are connections returned to the connection pool using Spring JPA (Hibernate) Entity Manager?

In my java process, I connect to MySql using the following spring configuration:

@Configuration @EnableTransactionManagement @PropertySources({ @PropertySource("classpath:/myProperties1.properties"), @PropertySource("classpath:/myProperties2.properties") }) public class MyConfiguration { @Autowired protected Environment env; /** * @return EntityManagerFactory for use with Hibernate JPA provider */ @Bean(destroyMethod = "destroy") public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource()); em.setJpaVendorAdapter(jpaVendorAdapter()); em.setPersistenceUnitManager(persistenceUnitManager()); return em; } /** * * @return jpaVendorAdapter that works in conjunction with the * persistence.xml */ @Bean public JpaVendorAdapter jpaVendorAdapter() { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setDatabase(Database.valueOf(env.getProperty("jpa.database"))); vendorAdapter.setDatabasePlatform(env.getProperty("jpa.dialect")); vendorAdapter.setGenerateDdl(env.getProperty("jpa.generateDdl", Boolean.class, false)); vendorAdapter.setShowSql(env.getProperty("jpa.showSql", Boolean.class, false)); return vendorAdapter; } @Bean public PersistenceUnitManager persistenceUnitManager() { DefaultPersistenceUnitManager pum = new DefaultPersistenceUnitManager(); pum.setPackagesToScan("com.app.dal"); pum.setDefaultPersistenceUnitName("my-pu"); pum.setPersistenceXmlLocations("classpath:/META-INF/persistence.xml"); pum.setDefaultDataSource(dataSource()); return pum; } @Bean(destroyMethod = "close") public DataSource dataSource() { Properties dsProps = new Properties(); dsProps.put("driverClassName", env.getProperty("hikari.driverClassName")); dsProps.put("username", env.getProperty("hikari.username")); dsProps.put("password", env.getProperty("hikari.password")); dsProps.put("jdbcUrl", env.getProperty("hikari.source.data.jdbcUrl")); dsProps.put("connectionTimeout", env.getProperty("hikari.connectionTimeout", Integer.class)); dsProps.put("idleTimeout", env.getProperty("hikari.idleTimeout", Integer.class)); dsProps.put("maxLifetime", env.getProperty("hikari.maxLifetime", Integer.class)); dsProps.put("maximumPoolSize", env.getProperty("hikari.maximumPoolSize.rtb.source", Integer.class)); dsProps.put("leakDetectionThreshold", env.getProperty("hikari.leakDetectionThreshold", Integer.class)); dsProps.put("jdbc4ConnectionTest", env.getProperty("hikari.jdbc4ConnectionTest", Boolean.class)); HikariConfig config = new HikariConfig(dsProps); HikariDataSource ds = new HikariDataSource(config); return ds; } @Bean(name = "sourceTxMgr") public PlatformTransactionManager sourceDatatransactionManager() { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setPersistenceUnitName("my-pu"); transactionManager.setDataSource(dataSource()); return transactionManager; } @Bean public PersistencyManager persistencyManager() { return new JpaPersistencyManager(); } @Bean public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { return new PersistenceExceptionTranslationPostProcessor(); } } 

Entity-Manager is introduced at the level of access to this container:

 @PersistenceContext(type = PersistenceContextType.TRANSACTION, unitName = "my-pu") private EntityManager myEntityManager; 

And my public business logic methods are annotated with @Transactional annotation.

As far as I understand, the container is responsible for the fact that the manager entity returns connections to the pool (in my case HikariCP ) after the transaction is completed, but I did not find the official documentation describing connection management. Can someone explain this to me or provide a good link that can explain exactly when the connections are returned to the pool when using this configuration?

UPDATE:

The best related information I could find so far ( taken here ):

The persistence context proxy that implements EntityManager is not the only component required to perform declarative transaction management. In fact, three separate components are needed:

EntityManager Proxy Transactional Aspect Transaction Manager Let's move on to each of them and see how they interact.

Transactional aspect

The Transactional Aspect is an “around” aspect that is invoked both before and after the annotated business method. The specific class for implementing the aspect is the TransactionInterceptor.

The transactional aspect has two main responsibilities:

At the “before” point, this aspect provides a reference point for determining whether the business method to be invoked should be launched as part of the current database transaction or if a new separate transaction needs to be started.

At the “after” point, the aspect should decide whether to commit the transaction, rollback, or leave it on the go.

At the time “before”, Transactional Aspect itself does not contain decision logic, the decision to start a new transaction is delegated to the transaction manager, if necessary.

Transaction manager

The transaction manager should provide an answer to two questions:

should a new Entity Manager be created? should a new database transaction be started? This must be resolved when the Transactional Aspect "before" logic is invoked. The transaction manager will make a decision based on:

the fact that one transaction is already ongoing or not the attribute of the distribution of the transaction method (for example, REQUIRES_NEW always starts a new transaction) If the transaction manager decides to create a new transaction, it will:

create a new object manager bind the object manager to the current thread grab the connection from the DB connection pool bind the connection to the current thread Object manager and the connection are bound to the current thread using ThreadLocal variables.

They are stored in the stream during the execution of the transaction, and before the transaction manager they clear them when they are no longer needed.

Any parts of the program that need a current manager or entity connection can extract them from the stream. One software component that does exactly this is the EntityManager proxy.

+25
java spring mysql hibernate jpa
source share
1 answer

This is not at all difficult.

  1. First, you must understand that Spring Transaction Manager is just an abstraction of transaction management . In your case, the actual transactions occur at the JDBC connection level.

  2. All calls to the @Transactional service method @Transactional intercepted by the TransactionInterceptor aspect.

  3. TransactionIntreceptor delegates transaction management to the currently configured AbstractPlatformTransactionManager implementation ( JpaTransactionManager in your case).

  4. JpaTransactionManager will associate the current Spring transaction in JpaTransactionManager with the EntityManager, so all DAOs participating in the current transaction use the same persistence context.

  5. JpaTransactionManager simply uses the EntityManager Transaction API to manage transactions:

     EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager().getTransaction(); tx.commit(); 

    The JPA Transaction API simply delegates a call to the underlying JDBC Connection commit / rollback methods.

  6. When the transaction is completed (commit / rollback), org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction calls:

     transactionCoordinator().getTransactionContext().managedClose(); 

    which causes the Hibernate Session (Entity Manager) to close.

  7. Therefore, the underlying JDBC connection also closes:

     jdbcCoordinator.close(); 
  8. Hibernate has a logical JDBC connection descriptor:

     @Override public Connection close() { LOG.tracev( "Closing JDBC container [{0}]", this ); if ( currentBatch != null ) { LOG.closingUnreleasedBatch(); currentBatch.release(); } cleanup(); return logicalConnection.close(); } 
  9. The logical connection delegates a close call to the currently configured connection provider (in your case, DataSourceConnectionProvider ), which simply calls the close method on the JDBC connection:

     @Override public void closeConnection(Connection connection) throws SQLException { connection.close(); } 
  10. Like any other DataSource connection pool , closing a JDBC connection simply returns the connection to the pool and does not close the physical database connection. This is because the DataSource connection pool returns a proxy for the JDBC connection, which intercepts all calls and delegates the closure to the connection pool processing logic.

You can also find more information about this topic and why you need to set the hibernate.connection.provider_disables_autocommit property using Hibernate in this article .

+35
source share

All Articles