本文由个人总结,如需转载使用请标明原著及原文地址
dynamic动态数据源+druid阿里连接池设置oracle.net.CONNECT_TIMEOUT失效的问题
dynamic动态数据源 oracle 出现socket read time out
出现问题的版本
bash
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.8</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.20</version>
</dependency>
在这版本下url: jdbc:oracle:thin:@//ip:1521/ORCL?oracle.net.CONNECT_TIMEOUT=60000配置不生效,直接说解决方案,如果有兴趣的话后面有排错过程
解决方案
将dynamic-datasource-spring-boot-starter的版本升到3.6.0以上,然后修改配置文件
注意,connect-timeout和socket-timeout都要配置,不然会报错
bash
spring:
datasource:
dynamic:
primary: master
datasource:
master:
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@//ip:1521/ORCL
username: xxx
password: xxx
type: com.alibaba.druid.pool.DruidDataSource
druid:
connect-timeout: 60000
socket-timeout: 60000
排错过程
DruidDataSourceCreator
DruidDataSourceCreator是dynamic中创建阿里连接池的类

可以看到,他在这设置了一些参数,然后调用了dataSource.init()
3.5.8版本的dynamic在这并没有设置connect-timeout和socket-timeout,所以无论你配置文件怎么配置,DruidDataSource的connect-timeout和socket-timeout都是0,接下来到了dataSource.init()里
DruidDataSource
DruidDataSource是阿里连接池的数据源,是com.alibaba.druid里的类
在init方法中,给connectTimeout和socketTimeout设置值的是红框的部分代码。由于DruidDataSourceCreator里没有调用DruidDataSource的setConnectTimeout和setSocketTimeout方法,所以connectTimeout和socketTimeout都是0。
此时connectTimeout和socketTimeout都会被设置为10000

initFromUrlOrProperties方法中也会修改connectTimeout和socketTimeout的值,但是只对mysql有效。mysql类型的数据源会从jdbcurl中读取connectTimeout和socketTimeout参数,也会从connectProperties里读取connectTimeout和socketTimeout参数但是前提是,你是mysql!!!!!oracle他没做任何操作!!!!!
所以此时connectTimeout和socketTimeout依旧都是10000,后续代码中没有再对connectTimeout和socketTimeout进行修改
init方法执行完成时connectTimeout和socketTimeout为10000

DruidAbstractDataSource
DruidAbstractDataSource是DruidDataSource继承的类,在执行sql前会调用createPhysicalConnection方法获取数据库连接

上一步我们知道创建出来的DruidDataSource的connectTimeout和socketTimeout都是10000,所以会进入上图代码里。
connectTimeoutStr在DruidDataSourceCreator中也没设置,所以是null
connectTimeoutStr会被设置为Integer.toString(this.connectTimeout)也就是10000
然后最坑的来了createPhysicalConnection方法里执行了physicalConnectProperties.put("oracle.net.CONNECT_TIMEOUT", this.connectTimeoutStr);把我们url上的oracle.net.CONNECT_TIMEOUT给覆盖了
所以不论你jdbcurl上怎么设置oracle.net.CONNECT_TIMEOUT属性,连接超时都会是10秒
dynamic创建DruidDataSource时,没有调用DruidDataSource的setConnectTimeout和setSocketTimeout方法
DruidDataSource自己又没有针对oracle的对connectTimeout和socketTimeout进行赋值
所以无论你怎么配置,创建出来的oracle数据源超时时间都是10秒
dynamic3.6.0
在3.6.0版本中支持了DruidDataSourceCreator的doCreateDataSource的setParam方法中,读取connectTimeout和socketTimeout字段对DruidDataSource进行赋值,所以升级版本后可以解决


旁门左道的方法
在不改变版本的情况下,我试过用自定义filter调用DruidDataSource的setConnectTimeout成功修改了dynamic+druid+oracle连接超时时间
代码我删了就不截图了
创建个filter继承阿里的FilterAdapter,加上@component
然后在配置文件里在filters里加上全路径类名
bash
spring:
datasource:
dynamic:
primary: master
datasource:
master:
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@//ip:1521/ORCL
username: xxx
password: xxx
type: com.alibaba.druid.pool.DruidDataSource
druid:
filters: stat,com.xxx.DruidCustomerFilter
init方法入参是DataSourceProxy实际入参是DruidDataSource,DruidDataSource有实现DataSourceProxy接口,可以把DataSourceProxy的dataSource强转成DruidDataSource然后调用setConnectTimeout方法,就能修改connectTimeout的值了
