druid 使用ojdbc8驱动连接数据库,密码错误时CreateConnectionThread无法退出

iqjalb3h  于 4个月前  发布在  Druid
关注(0)|答案(4)|浏览(66)

项目依赖

<dependency>
            <groupId>com.oracle.database.jdbc</groupId>
            <artifactId>ojdbc8</artifactId>
            <version>18.15.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>

测试代码

Thread(
        Runnable {
            var druidDataSource: DruidDataSource? = null
            val connectBO = ConnectBO("jdbc:oracle:thin:@10.10.xx.xx:1521/rac", "username", "errorpassword")
            try {
                druidDataSource = createDataSource(connectBO) as DruidDataSource
                druidDataSource.getConnection(2_000).use {
                    println(it)
                }
            } catch (e: Exception) {
                println(String.format("test connect error, url:[%s]", connectBO.url))
            } finally {
                druidDataSource?.close()
            }
        }
    ).start()
    Thread.sleep(100_000)
}

fun createDataSource(connectBO: ConnectBO): DataSource {
    val props = Properties().apply {
        this[DruidDataSourceFactory.PROP_DRIVERCLASSNAME] = oracle.jdbc.OracleDriver::class.qualifiedName!!
        this[DruidDataSourceFactory.PROP_USERNAME] = connectBO.username
        this[DruidDataSourceFactory.PROP_PASSWORD] = connectBO.password
        this[DruidDataSourceFactory.PROP_URL] = connectBO.url
    }
    props.setProperty(DruidDataSourceFactory.PROP_INITIALSIZE, "1")
    return DruidDataSourceFactory.createDataSource(props)
}

data class ConnectBO(val url: String, val username: String, val password: String)

问题现象

连接池中的CreateConnectionThread未正常关闭,持续创建连接并打印报错日志:

十一月 10, 2021 11:16:18 上午 com.alibaba.druid.pool.DruidDataSource error
严重: create connection SQLException, url: jdbc:oracle:thin:@10.10.xx.xx:1521/rac, errorCode 1017, state 72000
java.sql.SQLException: ORA-01017: invalid username/password; logon denied

	at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:494)
	at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:441)
	at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:436)
	at oracle.jdbc.driver.T4CTTIfun.processError(T4CTTIfun.java:1110)
	at oracle.jdbc.driver.T4CTTIoauthenticate.processError(T4CTTIoauthenticate.java:552)
	at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:540)
	at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:256)
	at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:501)
	at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:1297)
	at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:694)
	at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:782)
	at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:39)
	at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:704)
	at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1657)
	at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1723)
	at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2801)

原因分析

根据异常堆栈:

2021-10-11 11:39:24,343 ERROR - [com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2803)] create connection SQLException, url: jdbc:oracle:thin:@10.10.60.52:1521/pdb1, errorCode 17002, state 08006
java.sql.SQLRecoverableException: IO 错误: The Network Adapter could not establish the connection
	at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:774)
	at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:688)
	at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:39)
	at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:691)
	at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1657)
	at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1723)
	at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2801)
Caused by: oracle.net.ns.NetException: The Network Adapter could not establish the connection
	at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:523)
	at oracle.net.resolver.AddrResolution.resolveAndExecute(AddrResolution.java:521)
	at oracle.net.ns.NSProtocol.establishConnection(NSProtocol.java:660)
	at oracle.net.ns.NSProtocol.connect(NSProtocol.java:286)
	at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1438)
	at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:518)
	... 6 more
Caused by: java.io.IOException: Operation interrupted, socket connect lapse 0 ms. /10.10.xx.xx 1521 0 1 true
	at oracle.net.nt.TcpNTAdapter.connect(TcpNTAdapter.java:209)
	at oracle.net.nt.ConnOption.connect(ConnOption.java:161)
	at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:470)
	... 11 more
Caused by: java.io.InterruptedIOException: Operation interrupted
	at oracle.net.nt.TimeoutSocketChannel.handleInterrupt(TimeoutSocketChannel.java:311)
	at oracle.net.nt.TimeoutSocketChannel.<init>(TimeoutSocketChannel.java:84)
	at oracle.net.nt.TcpNTAdapter.connect(TcpNTAdapter.java:169)
	... 13 more

ojdbc8驱动在TimeoutSocketChannel#handleInterrupt方法中清除了线程中断标志,导致Druid的CreateConnectionThread无法在run方法中正常结束。
使用ojdbc6驱动则没有这个问题,Druid能否处理这种问题呢?

2nc8po8w

2nc8po8w1#

我现在升级到1.2.7了,还会有这个问题

vs3odd8k

vs3odd8k2#

使用MySQL驱动也遇到了CreateConnectionThread无法退出的问题。

驱动依赖:

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>

测试代码:

fun main() {
    Thread(
        Runnable {
            var druidDataSource: DruidDataSource? = null
            val connectBO =
                ConnectBO("jdbc:mysql://10.10.xx.xx:3306/test1?autoReconnect=true", "username", "password")
            try {
                druidDataSource = createDataSource(connectBO) as DruidDataSource
                druidDataSource.getConnection(2_000).use {
                    println(it)
                }
            } catch (e: Exception) {
                System.err.println(String.format("test connect error, url:[%s]", connectBO.url))
            } finally {
                druidDataSource?.close()
            }
        }
    ).start()
    Thread.sleep(100_000)
}

fun createDataSource(connectBO: ConnectBO): DataSource {
    val props = Properties().apply {
        this[DruidDataSourceFactory.PROP_USERNAME] = connectBO.username
        this[DruidDataSourceFactory.PROP_PASSWORD] = connectBO.password
        this[DruidDataSourceFactory.PROP_URL] = connectBO.url
    }
    props.setProperty(DruidDataSourceFactory.PROP_INITIALSIZE, "1")
    return DruidDataSourceFactory.createDataSource(props)
}

data class ConnectBO(val url: String, val username: String, val password: String)

当连接的数据库test1不存在时,调用close方法关闭连接池后,由于com.mysql.cj.jdbc.ConnectionImpl#connectWithRetries()方法的第906行捕捉并忽略了InterruptedException,导致Druid的CreateConnectionThread无法退出。

解决建议

能否在CreateConnectionThread的run方法中使用DruidDataSource的closed变量作为退出标识让CreateConnectionThread正确退出。

kpbpu008

kpbpu0083#

也遇到了 相同的问题,目前就只能设置 Druid 连接失败之后不再自动重连,Oracle 在里面把中断信号给丢了,或者说发送给 创建连接的线程的中断信号给Oracle给捕获了,从Oracle里面的逻辑上来看,Oracle 有自己的中断任务,如果中断任务不存在,会把中断信号给吞了。也是建议使用连接池的状态来控制创建线程和销毁线程的生命周期,中断信号一旦被其他线程,捕获之后是不可控的。

wn9m85ua

wn9m85ua4#

这个问题代码合入了吗?最新版本代码看着没合入:

相关问题