You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot用OracleDataSource连LDAP时重复抛出InvalidSyntaxException问题

Spring Boot + Oracle LDAP连接:InvalidSyntaxException异常重复抛出后成功连接

问题描述

我们有一个Spring Boot应用,使用Spring Data调用Oracle数据库中的存储过程。当应用访问数据库时,Dynatrace会捕获到oracle.net.jdbc.nl.InvalidSyntaxException异常,提示信息为:

TNS-***** Invalid syntax error: Expected "(" before or at , cn =

数据库连接URL

使用的LDAP格式连接URL示例:

jdbc:oracle:thin:@ldap://mydomain.com:938/DAFPRXHSUSR,cn=OracleContext,dc=eusovd,dc=com

该URL符合Oracle LDAP连接字符串语法规范。

异常现象与推测

未编写任何重试逻辑的情况下,该异常会被抛出两次,第三次尝试时数据库调用成功。我们怀疑原因可能是:

  • Oracle驱动Jar包内置了重试逻辑;
  • 相关库在执行我们编写的调用前会发起2次请求,而这两次请求存在语法问题。

进一步推测:驱动误将LDAP URL识别为TNS URL,失败两次后才成功连接,但不确定是最终识别出LDAP格式、将URL转换为TNS格式,还是前两次请求使用错误语法,第三次才用正确语法执行。

异常堆栈信息

Exception:
oracle.net.jdbc.nl.InvalidSyntaxException
Message:
TNS-***** Invalid syntax error: Expected "(" before or at , cn =
Stacktrace:
oracle.net.jdbc.nl.NVFactory._readTopLevelNVPair(NVFactory.java:97)
oracle.net.jdbc.nl.NVFactory.createNVPair(NVFactory.java:65)
oracle.jdbc.driver.PhysicalConnection.isDRCPConnection(PhysicalConnection.java:11325)
oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:1199)
oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:105)
oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:886)
oracle.jdbc.datasource.impl.OracleDataSource.getPhysicalConnection(OracleDataSource.java:707)
oracle.jdbc.datasource.impl.OracleDataSource.getConnection(OracleDataSource.java:381)
oracle.jdbc.datasource.impl.OracleDataSource.getConnectionInternal(OracleDataSource.java:2206)
oracle.jdbc.datasource.impl.OracleDataSource.getConnection(OracleDataSource.java:354)
oracle.jdbc.datasource.impl.OracleDataSource.getConnection(OracleDataSource.java:315)
org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:157)
org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:115)
org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:78)
org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:319)
org.springframework.jdbc.core.metadata.CallMetaDataProviderFactory.createMetaDataProvider(CallMetaDataProviderFactory.java:74)
org.springframework.jdbc.core.metadata.CallMetaDataContext.initializeMetaData(CallMetaDataContext.java:253)
org.springframework.jdbc.core.simple.AbstractJdbcCall.compileInternal(AbstractJdbcCall.java:314)
org.springframework.jdbc.core.simple.AbstractJdbcCall.compile(AbstractJdbcCall.java:297)
org.springframework.jdbc.core.simple.AbstractJdbcCall.checkCompiled(AbstractJdbcCall.java:356)
org.springframework.jdbc.core.simple.AbstractJdbcCall.doExecute(AbstractJdbcCall.java:383)
org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SimpleJdbcCall.java:187)
com.esrx.services.inventory.scanner.persistence.repository.impl.InventoryCountsRepositoryImpl.getSnapshotsList(InventoryCountsRepositoryImpl.java:70)
com.esrx.services.inventory.scanner.persistence.repository.impl.InventoryCountsRepositoryImpl$$FastClassBySpringCGLIB$$970dd8c.invoke(<generated>)
org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
com.esrx.services.inventory.scanner.persistence.repository.impl.InventoryCountsRepositoryImpl$$EnhancerBySpringCGLIB$$.getSnapshotsList
com.esrx.services.inventory.scanner.core.service.impl.InventoryCountsServiceImpl.getSnapshotsList(InventoryCountsServiceImpl.java:35)
com.esrx.services.inventory.scanner.web.controller.InventoryCountsController.getSnapshots(InventoryCountsController.java:56)
jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java)
jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

相关代码片段

存储过程调用代码

异常抛出在SimpleJdbcCall.execute()方法内:

SimpleJdbcCall jdbcCall = new SimpleJdbcCall(
                    dataSourcePool.getCurrentUserJdbcTemplate())
                    .withoutProcedureColumnMetaDataAccess()
                    .withSchemaName(Constants.SCHEMA_NAME)
                    .withCatalogName(Constants.CATALOG_NAME)
                    .withProcedureName(Constants.ASSIGN_COUNTSHEET_ROW)
                    .declareParameters(new SqlParameter(Constants.P_SNAPSHOT_ID, Types.NUMERIC),
                            new SqlParameter(Constants.P_COUNT_SHEET_NUMBER, Types.NUMERIC),
                            new SqlParameter(Constants.P_SEARCH_WHBIN, 
                            new SqlOutParameter("p_abbrv", Types.VARCHAR));

            SqlParameterSource paramsIn = new MapSqlParameterSource()
                    .addValue(Constants.P_SNAPSHOT_ID, pSnapshotId)
                    .addValue(Constants.P_COUNT_SHEET_NUMBER, pCountSheetNumber)
                    .addValue(Constants.P_SEARCH_WHBIN, searchWhbin);

            Map<String, Object> out = jdbcCall.execute(paramsIn);

数据源创建代码

异常仅抛出一次,第二次尝试成功,该数据源供所有数据库调用使用:

public OracleDataSource getDataSource(String username, String credential) throws SQLException {

        log.info("..:: --> Create DataSource <-- ::..");
        OracleDataSource dataSource = new OracleDataSource();
        dataSource.setUser(username);
        dataSource.setPassword(credential);
        dataSource.setURL(this.getUrl());

    //  dataSource.getFastConnectionFailoverEnabled();

        // Try to get the connection, if credentials are not valid it will
        // not connect and throw an SQLException
        try(OracleConnection connection = (OracleConnection) dataSource.getConnection()){
            
        }
        

        log.info("Succesful datasource creation for user {}", username);

        return dataSource;
    }

注:OracleDataSource是非池化的,这是应用的需求。

已测试环境

  • Java版本:8、11
  • Oracle数据库版本:19.0.0.0.0
  • Oracle驱动版本:ojdbc8 19.3.0.0、ojdbc11 23.5.0.24.07(均存在该问题)

已尝试方案

  • 升级Java和Oracle驱动版本,问题未解决;
  • 改用HikariDataSource(池化数据源)后问题消失,但因应用需支持多Oracle用户独立登录,而HikariDataSource仅支持单用户连接池,无法使用。

内容的提问来源于stack exchange,提问作者Carlos Avila

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:34:54