Docker MySQL在超时后丢弃表:连接关闭后不允许操作

Posted

技术标签:

【中文标题】Docker MySQL在超时后丢弃表:连接关闭后不允许操作【英文标题】:Docker MySQL drops tables after timeout: No operations allowed after connection closed 【发布时间】:2021-03-30 14:03:26 【问题描述】:

一个非常奇怪的情况。我正在使用 Spring Boot 和在 docker 容器中运行的 Spring Data JPA 和 mysql。启动应用程序后一切正常(数据库在启动时使用spring.jpa.hibernate.ddl-auto=create-drop 进行初始化)。

如果我让应用程序运行,大约 10 分钟后,当运行另一个请求时,我会返回 table doesn't exist。检查数据库,我可以看到所有表都消失了(架构仍然存在)!

日志在错误之前向我显示此警告:

2020-12-20 16:15:41.151  WARN 11018 --- [nio-8080-exec-4] com.zaxxer.hikari.pool.PoolBase          : myDS - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@67dd33b2 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2020-12-20 16:15:41.153  WARN 11018 --- [nio-8080-exec-4] com.zaxxer.hikari.pool.PoolBase          : myDS - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@3817c06d (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.
2020-12-20 16:15:41.155  WARN 11018 --- [nio-8080-exec-4] com.zaxxer.hikari.pool.PoolBase          : myDS - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@536cd1b2 (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.

然后:

2020-12-20 16:15:41.161  WARN 11018 --- [nio-8080-exec-4] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1146, SQLState: 42S02
2020-12-20 16:15:41.161 ERROR 11018 --- [nio-8080-exec-4] o.h.engine.jdbc.spi.SqlExceptionHelper   : Table 'tasker.account' doesn't exist
2020-12-20 16:15:41.173  INFO 11018 --- [nio-8080-exec-4] o.h.e.internal.DefaultLoadEventListener  : HHH000327: Error performing load command

我还在 application.properties 中添加了这个设置:

spring.datasource.hikari.max-lifetime=600000 匹配 mysql 的设置。

Docker 启动于:

docker run --name=mysql1 --restart on-failure -d mysql/mysql-server:8.0

注意:本地 mysql 实例永远不会发生这种情况(本机,不在 docker 中)

任何帮助将不胜感激。

【问题讨论】:

添加此设置似乎已经解决了问题:spring.datasource.hikari.max-lifetime=100000 而与 mySQL 值完全匹配的spring.datasource.hikari.max-lifetime=600000 不起作用。因此它是这个问题和create-drop的结合。 你的连接类型是什么? @Perimosh 连接类型?不知道你到底是什么意思,但它是 jdbc url:spring.datasource.url=jdbc:mysql://172.17.0.2:3306/tasker?useUnicode=yes&characterEncoding=UTF-8 是嵌入的吗?如果是,是 hsqldb、h2 还是 derby? @Perimosh 它是mysql 在 docker 上运行,如问题中所述。它不是 hsqldb、h2 或 derby。 【参考方案1】:

问题似乎出在这个设置中:

spring.datasource.hikari.max-lifetime

在 application.properties 中添加此设置似乎解决了问题:spring.datasource.hikari.max-lifetime=100000 而与 mySQL 值完全匹配的spring.datasource.hikari.max-lifetime=600000 不起作用 - 即导致表被删除。

【讨论】:

【参考方案2】:

create-drop 会在关闭 SessionFactory 时丢弃 schema,现在我们来看看 SessionFactory 关闭的部分,它可能与网络连接超时导致 SessionFactory 被 springboot 自动关闭有关。

你可以在你的 application.properties 中添加一个心跳来防止这种行为发生,这部分已经解决了我的生产环境中的很多问题,所以添加这个非常有帮助:

#HeartBeat the database so that connections don't die otherwise the connections die silently
#and when a query commes along the JPA will throw an error and keep throwing errors and a restart of the process
#is inevitable
spring.datasource.testWhileIdle=true
spring.datasource.test-on-borrow=true
spring.datasource.validationQuery=SELECT 1

我将在此处放置一个处理检查连接和池运行状况的答案的链接Connection to Db dies after >4<24 in spring-boot jpa hibernate

另一件事,因为这只是一个开发环境,您可以将 create-drop 更改为 create,这会将 springboot 配置为删除现有架构并在 springboot 应用程序启动时创建一个新架构,这样架构将永远不会被破坏当连接丢失时。

【讨论】:

【参考方案3】:

看看这个答案:

How does spring.jpa.hibernate.ddl-auto property exactly work in Spring?

当您使用create-drop 时,您可能对他回答的以下部分感兴趣:

通常在测试用例场景中,您可能会使用create-drop 所以 你创建你的模式,你的测试用例添加了一些模拟数据,你 运行你的测试,然后在测试用例清理期间,模式 对象被删除,留下一个空数据库。

【讨论】:

谢谢,但这并不能回答为什么应用程序仍在运行并且数据库在 10 分钟超时后被删除的问题。我使用create-drop 在本地以开发模式运行应用程序,它不是任何自动化测试的一部分。我启动应用程序,它超时,数据消失,但应用程序继续运行 create-drop 的值被传递给 Hibernate,其理解如下:“数据库模式将被删除并随后创建。关闭 SessionFactory 后,数据库模式将被删除。” - 我会说你的 SessionFactory 会在一段时间后关闭。你能在那里设置一个断点,看看是否会发生这种情况? 又一页试图解释spring.jpa.hibernate.ddl-auto=create-drop 的使用,显示表在SessionFactory#close() 被删除:javausecase.com/2017/09/03/hibernate-5-hbm2ddl-auto-explained 你也可以看看这个:dev.mysql.com/doc/refman/5.7/en/… 请注意,保留旧的超时值并仅将create-drop 更改为create 并不能解决问题。同样的情况 - 表被删除

以上是关于Docker MySQL在超时后丢弃表:连接关闭后不允许操作的主要内容,如果未能解决你的问题,请参考以下文章

用jdbc连接mysql数据库,执行程序一段时间后控制台报连接超时。why,如何解决!

Spring 的 JdbcTemplate 是不是在查询超时后关闭连接?

haproxy 超时机制

超时连接后如何关闭TCP连接?

jedis 连接超时后还需要关闭吗

HikariCP - MYSQL 连接关闭后不允许操作。可能考虑使用更短的 maxLifetime 值