最近工作需要用 Nacos 连接 Oracle 数据库,有两个方案,一个是使用最新版, 添加插件支持,还还一种是使用 Nacos 的多数据源分支,这个分支的 Nacos 版本是 1.4.2-SNAPSHOT,参考文章 ,坑就从这里开始了….

1、故障现象

Error creating bean with name 'jpaVendorAdapter' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is java.lang.NullPointerException
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:361)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:131)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1672)

2、导致原因

我的连接配置是:

spring.jpa.hibernate.naming.physical-strategy=com.alibaba.nacos.config.server.configuration.NacosPhysicalNamingStrategy
nacos.datasource.type=ORACLE
nacos.datasource.relational.dsList[0].url=jdbc:oracle:thin:@localhost:1521:ORCL
nacos.datasource.relational.dsList[0].username=nacos
nacos.datasource.relational.dsList[0].password=123456
nacos.datasource.relational.dsList[0].driver-class-name=oracle.jdbc.driver.OracleDriver
nacos.datasource.relational.dsList[0].hikari.connection-timeout=10000
nacos.datasource.relational.dsList[0].hikari.idle-timeout=120000
nacos.datasource.relational.dsList[0].hikari.max-lifetime=240000
nacos.datasource.relational.dsList[0].hikari.maximum-pool-size=20
nacos.datasource.relational.dsList[0].hikari.data-source-properties.cachePrepStmts=true
nacos.datasource.relational.dsList[0].hikari.data-source-properties.prepStmtCacheSize=250
nacos.datasource.relational.dsList[0].hikari.data-source-properties.prepStmtCacheSqlLimit=2048
nacos.datasource.relational.dsList[0].hikari.connection-test-query=SELECT 1 FROM dual

JVM启动参数设置为:-Dnacos.standalone=true

点击运行 nacos-feature_multiple_datasource_support/console/src/main/java/com/alibaba/nacos/Nacos.java, 就出现了如上报错,一开始以为是我数据库版本的问题,因为提供的数据库表初始化脚本是12c的,而我安装的是19c,以为是版本不适配的缘故。我用 MySQL 连接的方式测试了一下发现程序可以正常启动,所以猜测问题应该出在连接驱动 Jar 包版本上,但搜索好几篇文章后发现驱动版本是正常的,所以排除,又怀疑问题出在数据库连接信息上,但仔细比对参考的那篇文档后发现并没有错误,于是Debug程序,发现异常是出在通过连接池获取数据库连接上,获取连接失败,但我用其他的数据库连接工具是可以连接上数据库的,于是可排除数据库本身的问题。

后面想通过 JDBC 的方式测试一下,于是搜索了连接教程,发现 Oracle 的连接字符串还有好几种连接方式,有通过SID的,有通过服务名的,我最初看到的那篇教程是通过 SID 方式,但我的数据库配置的是通过服务名连接,于是修改连接字符串后程序就正常启动了。

JDBC连接Oracle rac数据库的写法:

格式一:jdbc:oracle:thin:@//:/<service_name> 格式二:jdbc:oracle:thin:@:: 格式三:jdbc:oracle:thin:@

格式一是通过 SERVICE_NAME 连接Oracle数据库,适合于单实例和RAC

格式二是通过实例名SID连接数据库,RAC环境下实例名不唯一,不能充分利用数据库资源

格式三为通过本地配置的TNSNAME,支持RAC

这个问题还是由于工作后没有接触过 Oracle 数据库,导致不熟悉出现此问题,特此记录下。

3、解决方案

将连接 URL 改为:jdbc:oracle:thin:@//:/<service_name> 这种格式,注意这里的格式,port后面:换成了/,这种格式是Oracle 推荐的格式,因为对于集群来说,每个节点的SID 是不一样的,但是SERVICE_NAME 确可以包含所有节点。

4、参考博客

Oracle JDBC 连接的几种方式

nacos适配oracle数据库

[nacos配置Oracle数据源](