Spring 引导:Jdbc javax.net.ssl.SSLException:在接收对等 close_notify 之前关闭入站

Spring Boot: Jdbc javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify

我目前正在学习更多关于在 Spring Boot webapp 中实现 JDBC 和使用数据库的知识,我遇到了 post 底部写的以下 Stack Trace。

我已经创建了一个简单的 Employee 模型,我正在尝试在我的 main() 所在的同一个 class 上执行一些数据库代码。模型和主要的 class 是整个项目中只有两个 java 文件。我正在尝试实现以下 运行() 代码,该代码覆盖了界面 CommandLineRunner 中的代码,但我没有得到应该在 log.info("Part A:"):

log.info("Part A:")
employees.forEach(employee -> {log.info(employee.toString());
        log.info("part a");});

--我注意到的事情:

我注意到堆栈跟踪开始之前日志的最后一行来自:"Thread-1" 而不是 "main"。我认为这意味着来自主线程以外的某个线程遇到错误并在正常关闭之前关闭了连接。

此外,我认为因为 HikariPool 在 "peer's close_notify" 之前关闭,我认为它指的是 HikariPool 的正常关闭,我看不到我一直试图获得的最后一点日志记录。我想看到的最后一点日志记录是已插入到我的数据库中的员工的日志记录。

我想看到的最后一点日志记录应该从这行代码中获得:

employees.forEach(employee -> {log.info(employee.toString());
        log.info("part a");});

--注意事项:

因为日志中的这一行,我以为我会看到员工被插入到我的数据库中,但是当我直接在 MySQL 命令行客户端上查询时,它返回一个空集:

2018-11-03 21:08:35.362  INFO 2408 --- [           main] c.j.jdbctest1.JdbcTest1Application       : rows affected: 1

我不明白为什么没有向数据库中插入任何内容时却影响了一行

堆栈跟踪和日志:(下面粘贴的堆栈跟踪实际上会重复多次,但为了简洁起见,我将其删除。)

2018-11-03 21:08:32.997  INFO 2408 --- [           main] c.j.jdbctest1.JdbcTest1Application       : Starting JdbcTest1Application on KitKat with PID 2408 (C:\Users\Nano\Downloads\jdbc-test1\jdbc-test1\target\classes started by Nano in C:\Users\Nano\Downloads\jdbc-test1\jdbc-test1)
2018-11-03 21:08:33.003  INFO 2408 --- [           main] c.j.jdbctest1.JdbcTest1Application       : No active profile set, falling back to default profiles: default
2018-11-03 21:08:33.770  INFO 2408 --- [           main] c.j.jdbctest1.JdbcTest1Application       : Started JdbcTest1Application in 1.024 seconds (JVM running for 1.778)
2018-11-03 21:08:33.770  INFO 2408 --- [           main] c.j.jdbctest1.JdbcTest1Application       : Creating tables
2018-11-03 21:08:33.770  INFO 2408 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2018-11-03 21:08:34.082  INFO 2408 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2018-11-03 21:08:35.135  INFO 2408 --- [           main] c.j.jdbctest1.JdbcTest1Application       : Inserting Baggins Hopkins
2018-11-03 21:08:35.362  INFO 2408 --- [           main] c.j.jdbctest1.JdbcTest1Application       : rows affected: 1
2018-11-03 21:08:35.362  INFO 2408 --- [           main] c.j.jdbctest1.JdbcTest1Application       : Querying for employee
2018-11-03 21:08:36.065  INFO 2408 --- [           main] c.j.jdbctest1.JdbcTest1Application       : Part A:
2018-11-03 21:08:36.065  INFO 2408 --- [       Thread-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
Sat Nov 03 21:08:36 KST 2018 WARN: Caught while disconnecting...

EXCEPTION STACK TRACE:



** BEGIN NESTED EXCEPTION ** 

javax.net.ssl.SSLException
MESSAGE: closing inbound before receiving peer's close_notify

STACKTRACE:

javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:129)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:308)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:255)
    at java.base/sun.security.ssl.SSLSocketImpl.shutdownInput(SSLSocketImpl.java:645)
    at java.base/sun.security.ssl.SSLSocketImpl.shutdownInput(SSLSocketImpl.java:624)
    at com.mysql.cj.protocol.a.NativeProtocol.quit(NativeProtocol.java:1312)
    at com.mysql.cj.NativeSession.quit(NativeSession.java:182)
    at com.mysql.cj.jdbc.ConnectionImpl.realClose(ConnectionImpl.java:1750)
    at com.mysql.cj.jdbc.ConnectionImpl.close(ConnectionImpl.java:720)
    at com.zaxxer.hikari.pool.PoolBase.quietlyCloseConnection(PoolBase.java:135)
    at com.zaxxer.hikari.pool.HikariPool.lambda$closeConnection(HikariPool.java:441)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)


** END NESTED EXCEPTION **

Java代码:

@SpringBootApplication
public class JdbcTest1Application implements CommandLineRunner {
    private static final Logger log = LoggerFactory.getLogger(JdbcTest1Application.class);

    @Autowired
    JdbcTemplate jdbcTemplate;

    public static void main(String[] args) {
        SpringApplication.run(JdbcTest1Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("Creating tables");

        jdbcTemplate.execute("DROP TABLE IF EXISTS employees");
        jdbcTemplate.execute("CREATE TABLE employees (emp_id int, name varchar(100), role varchar(100), status varchar(100))");

        log.info("Inserting Baggins Hopkins");
        int rowsAffected = jdbcTemplate.update("INSERT INTO EMPLOYEE(EMP_ID, NAME, ROLE, STATUS)"
                + " VALUES(1,'Baggins Hopkins','thief','WORKING')");
        log.info("rows affected: "+ Integer.toString(rowsAffected));
        log.info("Querying for employee");
        String sql = "SELECT emp_id,name,role,status FROM employees";
        List<Employee> employees = jdbcTemplate.query(sql,(rs, rowNum)-> 
        new Employee(rs.getInt("emp_id"), rs.getString("name"),
                rs.getString("role"),Status.valueOf(rs.getString("status"))));
        log.info("Part A:");
        employees.forEach(employee -> {log.info(employee.toString());
            log.info("part a");});

    }
}

此外,为了以防万一,我从 application.properties:

粘贴了这段代码
spring.datasource.url=jdbc:mysql://localhost:3306/employee_database
spring.datasource.username=employee
spring.datasource.password=employee
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

与数据库的 SSL 连接失败,请尝试将您的数据源 URL 更改为:

spring.datasource.url=jdbc:mysql://localhost:3306/employee_database?useSSL=false

为了解决这个问题,我大概用了三天时间。

(编辑:这是测试的解决方法,实际上并不是解决方案。)

起初,我从尝试为 mysql 配置我自己的 SSL 开始解决问题,为此我花了好几个小时。过了太多时间,我才意识到配置它与 Cmake 和 C++ 有关,这让我放弃了。这是非常令人沮丧的。但是我并没有放弃,并尝试通过一种尚未找到的方法完全禁用SSL。我最终确实找到了方法。这是:

  1. 您必须使用 MySQL 的旧密码。旧密码是 MySQL 在 5.7x 版本中验证内容的方式。

再次打开 MySQL 安装程序,并重新配置 MySQL 服务器设置。 当你到达那里时,你会看到这个屏幕:

The screen that you should get to

You might get some errors when reaching the final stage of the reconfiguration:

I had problems at the final stage I had no idea how to fix so I uninstalled MySQL altogether. I use windows. I deleted the MySQL project root directory from Program Files to uninstall MySQL. I also deleted the databases saved in Program Data (a hidden folder in the C Drive) because I wanted to start afresh(WARNING: this will delete all your previously saved data!). Uninstalling MySQL from the control panel might not be enough to completely erase MySQL from your computer.

  1. 删除 C:\ProgramData\MySQL\MySQL 服务器 8.0\Data 中的所有 *.pem 文件。 (或者把它移到别的地方,我就是这么做的)

You might not see ProgramData in the C Drive. That is because it is a hidden folder. In order to see hidden folders:

search for folder options in the control panel.

Go to view.

Under 'Advanced settings' and under 'Hidden files and folders' of that, click "Show hidden files, folders, and drives."

  1. 转到 C:\ProgramData\MySQL\MySQL Server 8.0 并打开 my.cnf(或 my.ini)。在 [mysqld] 后添加以下行:

ssl=0

然后保存。它现在应该可以工作了。

参考文献:

  1. https://community.atlassian.com/t5/Confluence-questions/MySQL-Public-Key-Retrieval-is-not-allowed/qaq-p/778956
  2. https://scalegrid.io/blog/configuring-and-managing-ssl-on-your-mysql-server/

该警告看起来像是 MySQL 驱动程序错误 Java 11 并启用了 SSL:https://bugs.mysql.com/bug.php?id=93590
由于驱动程序 警告 而停用加密是个坏主意。

虽然您的插入问题看起来更像是一个典型的事务问题,但我怀疑它与 SSL 警告有关。

我遇到了这个问题并决定使用 直到我通过将 Tomcat 从版本 9.0.12 更新到 9.0.16 不小心解决了它。

我也遇到了同样的问题。 如果您查看堆栈跟踪,就会清楚地提到要做什么 -

Sat Mar 16 09:00:01 IST 2019 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. 
You need either to explicitly disable SSL by setting **useSSL=false**, or set **useSSL=true** and provide truststore for server certificate verification.

所以在通过更改数据源禁用 ssl 后 url 解决了问题 -

spring.datasource.url=jdbc:mysql://localhost:3306/security?useSSL=false

当我将服务器中的 Java 版本从 8 升级到 11 时,我遇到了类似的问题。

spring 引导从 2.1 开始 supporting Java 11 及更高版本。因此,请确保您的项目的依赖项也相应更新。这与此答案相关,因为 SpringBoot 还会影响 MySQL 连接器、Hibernate 核心和其他依赖项。

无法连接到数据库导致出现更多 NoClassDefFoundErrors。因此,请确保先解决此问题,然后再查看其他错误。

SpringBoot starter 的 pom 依赖示例

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.12.RELEASE</version>
    <relativePath />
</parent>

希望这对某人有所帮助。

尝试使用以下 URL。正如他们建议使用 useSSL=false 此外,当您在 URL.

中定义了多个属性时,请确保使用 <&> 而不是 & 。

jdbc:mysql://localhost:3306/TestDB?serverTimezone=PST&amp;useSSL=false

我也遇到了同样的问题

但后来我将 mysql-connector-java 版本从 5.1.46 更新到 8.0.20,并将 com.mysql.jdbc.Driver 更改为 com.mysql.cj.jdbc.Driver 它解决了我的问题

我的相似度问题在spark, 我通过下载 java 版本解决了这个问题 'openjdk version "1.8.0_275"' 至 'openjdk version "1.8.0_265"', 希望对你有用

这对我有用

   <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
        <version>8.0.20</version>
    </dependency>

我在 tomcat 尝试通过 ssl 连接到 Aurora mysql (AWS)

时遇到类似问题

我通过将驱动程序版本从 'mysql-connector-java-5.1.40.jar' 更新到 'mysql-connector-java-5.1.49.jar' 并将根 CA 安装到 ceacerts 中解决了这个问题:

keytool -import -trustcacerts -file rds-ca-2019-root.pem -keystore /<your_java_home>/lib/security/cacerts

希望对你有用