【问题标题】:Connections increase after Hibernate upgradeHibernate 升级后连接增加
【发布时间】:2021-06-12 09:37:58
【问题描述】:

有一个包含 MySQL、Hibernate 和 HicariCP 组合的应用程序,用于使用 JTA 会话管理范例与数据库进行交互。 使用 WildFly 应用服务器运行的应用程序。 配置如下所示

@Configuration
@EnableTransactionManagement
@ComponentScan("XXX")
public class DatabaseConfig {

  @Bean
  public LocalSessionFactoryBean sessionFactory(CustomDatasource datasource) {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(datasource);
    sessionFactory.setPackagesToScan("XXX");
    sessionFactory.setHibernateProperties(hibernateProperties());
    return sessionFactory;
  }

  @Bean
  public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
    HibernateTransactionManager transactionManager = new HibernateTransactionManager();
    transactionManager.setSessionFactory(sessionFactory);
    return transactionManager;
  }

  @Bean
  public DefaultMergeEventListener mergeEventListener() {
    return new DefaultMergeEventListener();
  }

  private Properties hibernateProperties() {
    Properties properties = new Properties();
    properties.put("hibernate.current_session_context_class", "jta");
    properties.put("hibernate.transaction.factory_class", "org.hibernate.transaction.JTATransactionFactory");
    properties.put("hibernate.transaction.manager_lookup_class", "org.hibernate.transaction.JBossTransactionManagerLookup");
    properties.put("hibernate.transaction.jta.platform", "JBossAS");
    
    return properties;
  }

} 

在将 Hibernate 从 3.6.10.Final 升级到 5.1.17.Final 后,我们注意到从连接池中检索到的连接数显着增加。 出于验证目的,我们添加了一个计数器,用于记录 javax.sql.Datasource.getConnection() 执行的次数。

我们执行了涉及多个 API 的某些业务流程,并比较了升级前后的结果。有趣的是,每个 API 获得的连接数正好翻了一番。

就变化而言 - 只是依赖版本升级,更新了几个 hibernate 类包并在 Dao/Repository 级别添加了@Transactional 注解。没有别的了。

想知道 Hibernate 内部发生了什么变化导致了这种差异? 感谢任何帮助!

【问题讨论】:

    标签: java mysql hibernate transactions database-connection


    【解决方案1】:

    据我所知,没有变化。如果您说金额翻了一番,我会检查交易集成是否以某种方式“损坏”。也许您正在创建 2 笔交易,而之前您只创建了一个。当使用 Hibernate Session/EntityManager 进行查询时,您可能会看到这一点,因为之前您有一个较长的连接时间。

    【讨论】:

    • 感谢您的回答。我添加了更精确的指标收集器,发现连接检索增加了 25%。这里有 2 条新的痕迹似乎有助于增加 25%:SessionImpl@11.initializeCollection#2004<AbstractPersistentCollection$4@12.doWork#567<AbstractPersistentCollection@13.withTemporarySessionIfNeeded#249AbstractFlushingEventListener@11.performExecutions#337<DefaultFlushEventListener@12.onFlush#39<SessionImpl@13.flush#1295。第一个似乎与一些延迟初始化有关,第二个是刷新事件的事件侦听器。有什么想法吗?
    • 另外值得一提的是,我们使用的是 HibernateTemplate,而不是经典的 sessionFactory.getCurrentSession()。我会在这里检查它是否有任何区别
    • 如果没有看到代码或无法调试,真的很难说。我只能告诉你,这很可能是由一些集成代码引起的,因为它似乎是一个系统性的变化。
    【解决方案2】:

    据我目前所知,变化的要点在于连接分配机制。 为了更好地说明想法,这里是一个代码 sn-p:

      class UserService {
        public void createUser() {
          
          userRepository.saveUser();
          
          avatarService.createUserAvatar();
          invalidateAvatarCache();
          
          addressService.createUserAddress();
          invalidateAddressCache();
          
          paymentService.saveUserPaymentInfo();
          thirdpartyService.sendNotification();
        }
      }
    

    这不是很好的做法,但当前的用户创建过程是分阶段的。意思是,实体被一个一个地持久化到数据库,而不是一次提交/回滚所有内容。 当前方法有多个缺点,但这就是我们所处的位置。 之前(使用 Hibernate 3.6.x)我们根本没有使用 @Transactional。但是随着升级,我们至少需要用@Transactional 注释写操作。 因此,Repository/Dao 中每个刷新数据 (userRepository.saveUser, avatarService.createUserAvatar, addressService.createUserAddress and paymentService.saveUserPaymentInfo) 的底层方法都标有 @Transactional。

    话虽如此,每次我们进入事务方法时都会获取连接,这会导致整体更高的连接使用率。 只是为了实验,我已将 @Transactional 添加到整个 createUser 方法中,并且获得/释放的连接数似乎与给定 API 之前的连接数相当。但显然我们不能继续使用这个选项,因为作为代码流的一部分,我们使各种缓存无效,通知外部服务。这意味着对于失败的情况,缓存中的通知和数据将与存储在数据库中的内容不一致。

    所以,现在我正在寻找一种重新使用已经获得的连接的选项。有什么想法吗?

    附:与主题略有相关 - When are connections returned to the connection pool with Spring JPA (Hibernate) Entity Manager?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-19
      • 2022-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-14
      • 2013-10-28
      • 2017-10-15
      相关资源
      最近更新 更多