Java连接SQL Server显示SSL异常Caused by: java.io.IOException: SQL Server did not return a response. The connection has been closed.
一、故事背景
最近有个项目需要从数据库中查到对应信息并通过企业微信机器人将信息推送出来,本来是一个很简单的需求,竟遇到了一个小插曲。拿到了数据库地址并被告知是SQL Server数据库,但是在通过程序进行数据库连接测试时发生了报错
二、具体报错信息
INFO com.microsoft.sqlserver.jdbc.internals.TDS.Channel enableSSL 1651 - java.security path: /app/jdk/jre/lib/security
Security providers: [SUN version 1.8, SunRsaSign version 1.8, SunEC version 1.8, SunJSSE version 1.8, SunJCE version 1.8, SunJGSS version 1.8, SunSASL version 1.8, XMLDSig version 1.8, SunPCSC version 1.8]
SSLContext provider info: Sun JSSE provider(PKCS12, SunX509/PKIX key/trust factories, SSLv3/TLSv1/TLSv1.1/TLSv1.2)
SSLContext provider services:
[SunJSSE: KeyFactory.RSA -> sun.security.rsa.RSAKeyFactory
aliases: [1.2.840.113549.1.1, OID.1.2.840.113549.1.1]
, SunJSSE: KeyPairGenerator.RSA -> sun.security.rsa.RSAKeyPairGenerator
aliases: [1.2.840.113549.1.1, OID.1.2.840.113549.1.1]
, SunJSSE: Signature.MD2withRSA -> sun.security.rsa.RSASignature$MD2withRSA
aliases: [1.2.840.113549.1.1.2, OID.1.2.840.113549.1.1.2]
, SunJSSE: Signature.MD5withRSA -> sun.security.rsa.RSASignature$MD5withRSA
aliases: [1.2.840.113549.1.1.4, OID.1.2.840.113549.1.1.4]
, SunJSSE: Signature.SHA1withRSA -> sun.security.rsa.RSASignature$SHA1withRSA
aliases: [1.2.840.113549.1.1.5, OID.1.2.840.113549.1.1.5, 1.3.14.3.2.29, OID.1.3.14.3.2.29]
, SunJSSE: Signature.MD5andSHA1withRSA -> sun.security.ssl.RSASignature
, SunJSSE: KeyManagerFactory.SunX509 -> sun.security.ssl.KeyManagerFactoryImpl$SunX509
, SunJSSE: KeyManagerFactory.NewSunX509 -> sun.security.ssl.KeyManagerFactoryImpl$X509
aliases: [PKIX]
, SunJSSE: TrustManagerFactory.SunX509 -> sun.security.ssl.TrustManagerFactoryImpl$SimpleFactory
, SunJSSE: TrustManagerFactory.PKIX -> sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory
aliases: [SunPKIX, X509, X.509]
, SunJSSE: SSLContext.TLSv1 -> sun.security.ssl.SSLContextImpl$TLS10Context
aliases: [SSLv3]
, SunJSSE: SSLContext.TLSv1.1 -> sun.security.ssl.SSLContextImpl$TLS11Context
, SunJSSE: SSLContext.TLSv1.2 -> sun.security.ssl.SSLContextImpl$TLS12Context
, SunJSSE: SSLContext.TLS -> sun.security.ssl.SSLContextImpl$TLSContext
aliases: [SSL]
, SunJSSE: SSLContext.Default -> sun.security.ssl.SSLContextImpl$DefaultSSLContext
, SunJSSE: KeyStore.PKCS12 -> sun.security.pkcs12.PKCS12KeyStore
]
java.ext.dirs: /app/jdk/jre/lib/ext:/usr/java/packages/lib/ext
[2024-07-16 13:50:07.900] ERROR com.alibaba.druid.pool.DruidDataSource run 2912 - create connection SQLException, url: jdbc:sqlserver://xxx.xx.xxx.xxx:1433;DatabaseName=weight, errorCode 0, state 08S01
com.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "SQL Server did not return a response. The connection has been closed. ClientConnectionId:941656ae-9767-4121-82b1-cb7ceef27a30".
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1667)
at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1668)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:1323)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:991)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:827)
at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:1012)
at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:118)
at com.alibaba.druid.filter.stat.StatFilter.connection_connect(StatFilter.java:232)
at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:112)
at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1703)
at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1786)
at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2910)
Caused by: java.io.IOException: SQL Server did not return a response. The connection has been closed. ClientConnectionId:941656ae-9767-4121-82b1-cb7ceef27a30
at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.ensureSSLPayload(IOBuffer.java:651)
at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.readInternal(IOBuffer.java:708)
at com.microsoft.sqlserver.jdbc.TDSChannel$SSLHandshakeInputStream.read(IOBuffer.java:700)
at com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.readInternal(IOBuffer.java:895)
at com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.read(IOBuffer.java:883)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1618)
... 10 common frames omitted
三、问题排查
-
确认网络环境畅通
通过telnet ip 端口命令以及沟通负责网络的同事确认网络环境畅通
-
更换多个pom依赖版本无效
一开始想当然的认为是依赖的版本问题,于是在这里花了大量时间进行测试
-
禁用SSL无效
这里将url后面加上;encrypt=false;trustServerCertificate=true用于禁用SSL仍无效
四、问题解决
后续直接通过DataGrip进行连接测试,一开始测试连接也是报错
在点开Driver后看到有多个不同Dirver于是选择了jTds的驱动再试了下,竟然测试成功了。由此知道了问题所在。
那么我们先了解下这两种驱动程序有何区别
Microsoft SQL Server (jTds) 和 Microsoft SQL Server 驱动程序之间的主要区别如下:
Microsoft SQL Server (jTds)
开源:jTDS 是一个开源的 JDBC 驱动程序,支持 Microsoft SQL Server 和 Sybase。
性能:在某些情况下,jTDS 的性能可能优于 Microsoft 官方驱动程序,特别是在处理批量操作时。
功能:jTDS 支持的功能可能不如 Microsoft 官方驱动程序全面,特别是在新版本的 SQL Server 中。
社区支持:由于是开源项目,jTDS 的更新和支持主要依赖于社区贡献,更新频率可能较低。
Microsoft SQL Server (mssql-jdbc)
官方支持:这是 Microsoft 官方提供的 JDBC 驱动程序,专门为 SQL Server 设计和优化。
功能全面:官方驱动程序通常支持 SQL Server 的所有最新功能和特性,包括高级安全性、加密、集成身份验证等。
更新频率:官方驱动程序由 Microsoft 维护,更新频率较高,能够及时支持 SQL Server 的新版本和新特性。
兼容性:官方驱动程序在兼容性和稳定性方面通常表现更好,特别是在与其他 Microsoft 产品集成时。
选择建议
使用 jTDS:如果你需要一个开源解决方案,或者在特定场景下 jTDS 的性能表现更好,可以选择 jTDS。
使用 mssql-jdbc:如果你需要全面的功能支持、官方支持和更好的兼容性,建议使用 Microsoft 官方的 mssql-jdbc 驱动程序。
正确的pom依赖以及数据库url
<!--jtds驱动-->
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<!--选择合适的版本-->
<version>1.3.1</version>
</dependency>
driver-class-name: net.sourceforge.jtds.jdbc.Driver
url: jdbc:jtds:sqlserver://xxx.xx.xxx.xxx:1433/weight
username: xx
password: xxxxxxx
更换了正确的依赖和url后报错即解决