【问题标题】:ORA-02396: exceeded maximum idle when several DS and Hikari usedORA-02396: 使用多个 DS 和 Hikari 时超出最大空闲
【发布时间】:2021-11-08 08:50:26
【问题描述】:

我们有多个系统,使用相同的核心库和相同的 Oracle 数据库。但是每天只有一个系统出现错误,下面是堆栈跟踪。

错误是:ORA-04042: procedure, function, package, or package body does not exist。该系统与其他系统的不同之处在于,该系统使用了多个数据源,您可以在下面看到 Hikari 配置、build.gradle 和堆栈跟踪的一部分。所有其他系统都使用一个数据源。

这是 Oracle 版本信息:

BANNER                                                                               CON_ID
-------------------------------------------------------------------------------- ----------
Oracle Database 12c Release 12.1.0.1.0 - 64bit Production                                 0
PL/SQL Release 12.1.0.1.0 - Production                                                    0
CORE    12.1.0.1.0  Production                                                            0
TNS for 64-bit Windows: Version 12.1.0.1.0 - Production                                   0
NLSRTL Version 12.1.0.1.0 - Production                                                    0

这是用于配置数据源之一的代码。第二个以同样的方式生产:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
  entityManagerFactoryRef = "sourceEntityManagerFactory",
  transactionManagerRef = "sourceTransactionManager",
  basePackages = { "com.maxi.jpa.source" }
)
public class SourceConfig
{
    @Bean(name = "sourceDS")
    @Primary
    @ConfigurationProperties("spring.datasource.ds-src")
    public DataSource dataSource(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "sourceEntityManagerFactory")
    @DependsOn("sourceDS")
    @Primary
    public LocalContainerEntityManagerFactoryBean sourceEMF(
        EntityManagerFactoryBuilder builder,
        @Qualifier("sourceDS")
        DataSource ds
    ) {
        return builder
            .dataSource(ds)
            .packages("com.maxi.jpa.model")
            .persistenceUnit("source")
            .build();
    }

    @Bean(name = "sourceEntityManager")
    @Primary
    public EntityManager sourceEM(
        @Qualifier("sourceEntityManagerFactory")
        EntityManagerFactory factory
    ) {
        return factory.createEntityManager();
    }

    @Bean(name = "sourceTransactionManager")
    @Primary
    public PlatformTransactionManager transactionManager(
        @Qualifier("sourceEntityManagerFactory") EntityManagerFactory
        entityManagerFactory
    ) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

以下是异常所在的代码:

private List<String> descTable(String owner, String tableName) {
    String query =
        "select column_name " +
        "from all_tab_columns " +
        "where upper(owner) = '%s' " +
        "and upper(table_name) = '%s'";

    query = String.format(query, owner, tableName);

    @SuppressWarnings("unchecked")
    List<String> result = (List<String>)sourceEntityManager
        .createNativeQuery(query)
        .getResultList();

    return result;
}

这样,我注入sourceEntityManager

@Service
public class DMLService
{
    private EntityManager sourceEntityManager;
    private EntityManager destEntityManager;

    public DMLService(
        @Qualifier("sourceEntityManager")
        EntityManager sourceEntityManager,
        @Qualifier("destEntityManager")
        EntityManager destEntityManager
    ) {
        this.sourceEntityManager = sourceEntityManager;
        this.destEntityManager = destEntityManager;
    }

    ....
}

application.yaml

spring:
  datasource:
    ds-src:
      driverClassName: oracle.jdbc.OracleDriver
      jdbcUrl: jdbc:oracle:thin:@${DB4VAL_SRC_DB}
      username: ${DB4VAL_SRC_USERNAME}
      password: ${DB4VAL_SRC_PASSWORD}
      poolName: Db4ValidateSource
      connectionTestQuery: SELECT 1 FROM DUAL
    ds-dest:
      driverClassName: oracle.jdbc.OracleDriver
      jdbcUrl: jdbc:oracle:thin:@${DB4VAL_DEST_DB}
      username: ${DB4VAL_DEST_USERNAME}
      password: ${DB4VAL_DEST_PASSWORD}
      poolName: Db4ValidateDestination
      connectionTestQuery: SELECT 1 FROM DUAL
  jpa:
    database-platform: org.hibernate.dialect.Oracle12cDialect

application-default.yaml

spring:
  datasource:
    ds-src:
      minimumIdle: 1
      maximumPoolSize: 5
      idleTimeout: 20000
      maxLifetime: 60000
      keepaliveTime: 10000
      connectionTimeout: 30000
    ds-dest:
      minimumIdle: 1
      maximumPoolSize: 5
      idleTimeout: 20000
      maxLifetime: 60000
      keepaliveTime: 10000
      connectionTimeout: 30000

build.gradle

dependencies {
    implementation 'org.apache.commons:commons-lang3'
    implementation 'commons-net:commons-net:3.6'
    implementation 'commons-io:commons-io:2.6'
    implementation 'com.zaxxer:HikariCP:4.0.2'

    implementation 'org.springframework:spring-context-support'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    ...
}

stacktrace

at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:628)
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:557)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:730)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:291)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:492)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:148)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:928)
at oracle.jdbc.driver.OracleStatement.prepareDefineBufferAndExecute(OracleStatement.java:1158)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1093)
at oracle.jdbc.driver.OracleStatement.executeSQLSelect(OracleStatement.java:1402)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1285)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3735)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3847)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1098)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57)
at org.hibernate.loader.Loader.getResultSet(Loader.java:2297)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2050)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2012)
at org.hibernate.loader.Loader.doQuery(Loader.java:948)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:349)
at org.hibernate.loader.Loader.doList(Loader.java:2843)
at org.hibernate.loader.Loader.doList(Loader.java:2825)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2657)
at org.hibernate.loader.Loader.list(Loader.java:2652)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:338)
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2141)
at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1169)
at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:176)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1604)
at org.hibernate.query.Query.getResultList(Query.java:165)
at com.maxi.services.DMLService.descTable(DMLService.java:77)
at com.maxi.services.DMLService.getTableData(DMLService.java:191)
at com.maxi.services.DMLService.processRecord(DMLService.java:203)
at com.maxi.services.ValidateService.processRecord(ValidateService.java:263)
at com.maxi.services.ValidateService.runETL(ValidateService.java:362)
at com.maxi.services.Handler.runProcess(Handler.java:54)
at com.maxi.services.Handler.lambda$handleRequest$0(Handler.java:35)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

如您所见,系统捕获所有配置

【问题讨论】:

  • 添加完整的堆栈跟踪并分享您是如何注入 sourceEntityManager 的
  • 我在注入 bean 的位置添加了代码,并添加了堆栈跟踪的其余部分。
  • 您的标题显示“ORA-02396:超出最大空闲”,但在描述中“错误是:ORA-04042”我很困惑实际错误是什么。也缺少完整的堆栈跟踪
  • 这是实际错误和完整的堆栈跟踪。

标签: spring-boot oracle12c hikaricp


【解决方案1】:

所以,问题是,EntityManager 从池中检索连接,并且不返回它,直到它被关闭。但是我们不能手动关闭它,因为它是一个 bean,我们可能无法重新打开。

因此解决方案不是手动创建 EM,而是使用 @PersistenceContext(unitName = "unit_name") 从框架中获取它。

有必要删除此代码(对于两个 EM):

@Bean(name = "sourceEntityManager")
@Primary
public EntityManager sourceEM(
    @Qualifier("sourceEntityManagerFactory")
    EntityManagerFactory factory
) {
    return factory.createEntityManager();
}

@Bean(name = "sourceTransactionManager")
@Primary
public PlatformTransactionManager transactionManager(
    @Qualifier("sourceEntityManagerFactory") EntityManagerFactory
    entityManagerFactory
) {
    return new JpaTransactionManager(entityManagerFactory);
}

然后通过以下方式Autowire bean:

@PersistenceContext(unitName = "source")
private EntityManager sourceEntityManager;
@PersistenceContext(unitName = "destination")
private EntityManager destEntityManager;

不要忘记重写代码以使用@Transactionsjpaspring)。将注释放在公共方法或整个类上。

【讨论】:

    猜你喜欢
    • 2014-04-15
    • 2022-10-04
    • 2017-07-19
    • 2011-01-31
    • 1970-01-01
    • 2015-04-26
    • 2010-12-07
    • 2011-08-14
    • 2021-12-28
    相关资源
    最近更新 更多