春季启动:Jdbc javax.net.ssl.SSLException:在接收对等方的close_notify之前关闭入站

时间:2018-11-03 12:29:48

标签: mysql spring-boot spring-jdbc jdbctemplate sslexception

我目前正在学习有关在Spring Boot Webapp中实现JDBC和使用数据库的更多信息,并且在帖子底部遇到了以下堆栈跟踪。

我创建了一个简单的Employee模型,并试图在main()所在的同一类上执行一些数据库代码。该模型和main类是整个项目中仅有的两个Java文件。我正在尝试实现下面的run()代码,以覆盖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 Command Line Client上查询时,它返回了一个空集:

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

我不明白为什么在没有任何内容插入数据库的情况下行会受到影响

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

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$1(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

11 个答案:

答案 0 :(得分:36)

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

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

答案 1 :(得分:5)

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

您的插入问题看起来更像是经典的事务问题,我怀疑这与SSL警告有关。

答案 2 :(得分:4)

这对我有用

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

答案 3 :(得分:2)

要解决此问题,我花了大约三天的时间。

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

首先,我开始尝试通过为mysql配置我自己的SSL来解决问题,并且花了很多时间。直到我意识到配置它与Cmake和C ++有关,已经花费了太多时间,这使我放弃了。真令人沮丧。但是,我没有放弃,而是尝试通过一种尚未发现的方法完全禁用SSL。我最终找到了方法。在这里:

  1. 您必须使用MySQL的旧密码。遗留密码是MySQL在5.7x版中对事物进行身份验证的方式。

再次打开MySQL安装程序,然后重新配置MySQL Server设置。 当您到达那里时,将看到以下屏幕:

The screen that you should get to

  

到达重新配置的最后阶段时,您可能会遇到一些错误:

     

在最后阶段我遇到了问题,我不知道如何解决,所以我完全卸载了MySQL。我用窗户。我从“程序文件”中删除了MySQL项目的根目录,以卸载MySQL。我还删除了保存在程序数据(C盘中的隐藏文件夹)中的数据库,因为我想重新启动(警告:这将删除您以前保存的所有数据!)。从控制面板上卸载MySQL可能不足以从计算机上完全删除MySQL。

  1. 删除C:\ ProgramData \ MySQL \ MySQL Server 8.0 \ Data中的所有* .pem文件。 (或将其移动到其他地方,这是我所做的)
  

您可能在C驱动器中看不到ProgramData。那是因为它是一个隐藏的文件夹。为了查看隐藏的文件夹:

     

在控制面板中搜索文件夹选项。

     

查看。

     

在“高级设置”下的“隐藏文件和文件夹”下,单击“显示隐藏的文件,文件夹和驱动器”。

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

ssl = 0

然后保存。现在应该可以使用了。

编辑: 我意识到更新查询的SQL语法错误。我插入了错误的表。我认为无论是否解决SSLException问题,插入数据库都可能仍然有效。 (我不确定...)

参考文献:

  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/

答案 4 :(得分:2)

尝试使用以下URL。正如他们建议使用useSSL = false一样,当您在URL中定义了多个属性时,请确保使用<&amp>而不是&。

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

答案 5 :(得分:1)

我也面临同样的问题。 如果您查看堆栈跟踪,很明显提到了该怎么做-

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.

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

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

答案 6 :(得分:0)

我遇到了这个问题,并决定使用Carrier Pigeon Protocol's solution,直到我通过将Tomcat从9.0.12版本更新到9.0.16意外解决了这个问题。

答案 7 :(得分:0)

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

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

无法连接到数据库导致了更多的NoClassDefFoundErrors。因此,请确保在解决其他错误之前先解决此问题。

SpringBoot启动器的pom依赖示例

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

希望这对某人有帮助。

答案 8 :(得分:0)

我也面临着同样的问题

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

答案 9 :(得分:0)

我的相似之处充满了火花, 我通过降低Java版本来解决这个问题 'openjdk版本“ 1.8.0_275””到“ openjdk版本“ 1.8.0_265””, 希望对你有用

答案 10 :(得分:0)

我在尝试通过 ssl 连接到 Aurora mysql (AWS) 的 tomcat 中的类似问题

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

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

希望对你有用