当前位置: 首页 > 知识库问答 >
问题:

何时使用Spring JPA(Hibernate)实体管理器将连接返回到连接池?

汪甫
2023-03-14

在我的java进程中,我使用以下spring配置连接到MySql:

@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由容器注入到数据访问层:

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

并且我的公共业务逻辑方法使用@transactional注释进行了注释。

据我所知,容器负责确保实体管理器在事务完成后将连接返回到池(在我的例子中是HikariCP),但我没有找到任何描述如何管理连接的官方文档。有没有人可以给我解释一下,或者提供一个很好的参考,可以说明使用这样的配置时,连接到底是什么时候返回到池的?

更新:

到目前为止,我能得到的最好的相关信息(取自这里):

事务性方面有两个主要职责:

在'before'时刻,方面提供了一个钩子点,用于确定将要调用的业务方法是否应该在正在进行的数据库事务的范围内运行,或者是否应该启动一个新的单独事务。

在“after”时刻,方面需要决定事务是应该提交、回滚还是保持运行。

是否应创建新的实体管理器?是否应该启动新的数据库事务?这需要在调用逻辑之前确定事务方面。事务管理器将根据以下因素作出决定:

如果事务管理器决定创建一个新事务,那么它将:

创建一个新的实体管理器,将实体管理器绑定到当前线程,从DB连接池中抓取一个连接,将连接绑定到当前线程实体管理器和连接都使用ThreadLocal变量绑定到当前线程。

程序中需要当前实体管理器或连接的任何部分都可以从线程中检索它们。其中一个程序组件就是EntityManager代理。

共有1个答案

蓬新
2023-03-14

一点也不复杂。

>

  • 首先,您需要理解Spring事务管理器只是一个事务管理抽象。在您的例子中,实际事务发生在JDBC连接级别。

    所有@transaction服务方法调用都由transactioninterceptor方面拦截。

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

    当事务完成(提交/回滚)时,org.hibernate.engine.transaction.internal.jdbc.jdbctransaction调用:

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

    这将触发Hibernate会话(实体管理器)关闭。

    因此,底层JDBC连接也会被触发关闭:

     jdbcCoordinator.close();
    
     @Override
     public Connection close() {
         LOG.tracev( "Closing JDBC container [{0}]", this );
         if ( currentBatch != null ) {
         LOG.closingUnreleasedBatch();
             currentBatch.release();
         }
         cleanup();
         return logicalConnection.close();
     }
    
     @Override
     public void closeConnection(Connection connection) throws SQLException {
          connection.close();
     }
    

    注意,对于RESOURCE_LOCAL事务,如果autocommit检查被连接池禁用,则还应设置hibernate.connection.provider_disables_autocommit属性。这样,就会在执行SQL查询或刷新持久性上下文之前懒洋洋地获取数据库连接。

  •  类似资料:
    • 问题内容: 在我的Java进程中,我使用以下spring配置连接到MySql: Entity-Manager通过容器注入到数据访问层: 并且我的公共业务逻辑方法带有注释。 据我了解,容器负责确保一旦交易完成,实体管理器将连接返回到池(在我的情况下为HikariCP),但是我没有找到任何描述连接管理方式的官方文档。有人可以给我解释一下,还是可以提供很好的参考资料来说明使用这种配置时何时将确切的连接返

    • AnsprechPartner Lieferant ansprechpartner.java lieferant.java 在我的AnsprechPartner.java中,我是这样做的: 在我的Lieferanten.java中,我是这样做的:

    • 使用来自DBCP的BasicDataSource,如果我们执行getConnection()并且在最后一个块中我们关闭连接,它是真的将连接返回到池还是关闭连接。我正在检查的代码片段是这样的 我正在检查BasicDataSource的源代码,并访问了这个包装类以获取连接。 委托对象的类型为java。sql。联系包装器代码调用委托的close方法,该方法将关闭集合,而不是将连接返回到池。这是DBCP的

    • 我试图连接到mysql数据库使用hibernate从cfg文件作为 虽然我的连接字符串、用户名、密码是正确的,并且在其他具有基本jdbc连接的项目中运行良好,但当我使用hibernate尝试它时,我在控制台上遇到了这个错误 是的,数据库服务器已启动并运行,但来自此Hibernate应用程序的连接被拒绝

    • 我们正在用Java重写来自PHP的web应用程序。我认为,但我不是很确定,我们可能会在连接池方面遇到问题。应用程序本身是多租户的,是“独立数据库”和“独立模式”的组合。 对于每个Postgres数据库服务器实例,可以有一个以上的数据库(命名为schemax_XXX),其中包含一个以上的模式(模式是租户)。注册时,可能会发生以下两种情况之一: 在编号最高的schema_XXX数据库中创建新的租户模式