简体   繁体   English

Hibernate失去连接

[英]Hibernate loses connection

I am using hibernate to connect my mysql database and perform transactions. 我正在使用hibernate连接我的mysql数据库并执行事务。

I am using a single SessionFactory throughout the application and i don't have other connections to the database, yet, i am receiving the exception below: 我在整个应用程序中使用单个SessionFactory,并且我没有与数据库的其他连接,但是,我收到以下异常:

java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3008)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3466)
    ... 21 common frames omitted
Wrapped by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 526 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
    at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:989)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3556)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3456)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3897)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2524)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2677)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2545)
    at com.mysql.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl.java:4842)
    at org.hibernate.engine.jdbc.connections.internal.PooledConnections.poll(PooledConnections.java:84)
    at org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl.getConnection(DriverManagerConnectionProviderImpl.java:186)
    at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:35)
    at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:99)
    ... 11 common frames omitted
Wrapped by: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
    at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:115)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
    at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:102)
    at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:129)
    at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:247)
    at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:254)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:203)
    at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:56)
    at org.hibernate.internal.AbstractSharedSessionContract.beginTransaction(AbstractSharedSessionContract.java:387)
    at com.kitaplist.common.book.dao.HibernateBookDao.find(HibernateBookDao.java:56)
    at com.kitaplist.common.Collector.lambda$collectMetaBooksAndNewBooks$1(Collector.java:137)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

This is how i create my SessionFactory: 这就是我创建SessionFactory的方法:

public static SessionFactory getSessionFactory() {

    if (sessionFactory == null) {
        sessionFactory = new Configuration()
                .configure()
                .addAnnotatedClass(Seller.class)
                .addAnnotatedClass(Book.class)
                .buildSessionFactory();
    }

    return sessionFactory;
}

and here is the function that I use in my BookDao: 这是我在BookDao中使用的功能:

@Override
public void save(Book book) {
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    try {
        session.save(book);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }
}

my application is a crawler crawls a book object from web and saves the object to the database through the above save function. 我的应用程序是一个爬虫从Web抓取一个书对象,并通过上面的保存功能将对象保存到数据库。 I couldn't find the reason behind this exception. 我找不到这个例外背后的原因。

on the command console, i can see that the connection is re-established after it is lost, here : 在命令控制台上,我可以看到连接在丢失后重新建立,这里:

SLF4J: A number (289) of logging calls during the initialization phase have been intercepted and are
SLF4J: now being replayed. These are subject to the filtering rules of the underlying logging system.
SLF4J: See also http://www.slf4j.org/codes.html#replay
Wed Mar 14 16:36:29 UTC 2018 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.
Wed Mar 14 16:36:29 UTC 2018 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.
Wed Mar 14 16:36:30 UTC 2018 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.
Wed Mar 14 16:36:29 UTC 2018 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.


Wed Mar 14 16:47:14 UTC 2018 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.

Wed Mar 14 16:47:17 UTC 2018 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.

I would appreciate any help. 我将不胜感激任何帮助。

Since your problem involves network the best idea might be to add a JDBC connection pool to your setup. 由于您的问题涉及网络,因此最好的想法可能是在您的设置中添加JDBC连接池。 This will ensure that connections don't get stale while your application is running eg due to database server-side timeout. 这将确保在应用程序运行时连接不会过时,例如由于数据库服务器端超时。

HikariCP is by far my favourite pool as it sets sensible defaults eg on-borrow connection validation that can't be disabled. HikariCP是迄今为止我最喜欢的池,因为它设置合理的默认值,例如无法禁用的on- borrow连接验证。 Since you are using Hibernate, HikariCP shows how to set everything up on their wiki page . 由于您使用的是Hibernate,HikariCP会显示如何在其Wiki页面上设置所有内容。 The right setup however might depend on other libraries you are using eg shared java.sql.DataSource bean in Spring Boot. 但是,正确的设置可能取决于您正在使用的其他库,例如Spring Boot中的共享java.sql.DataSource bean。

There are other pooling libraries you can use but please take few minutes to read below before going that route: 您可以使用其他池库,但在走这条路线之前请花几分钟时间阅读:

If using a pooling library with on-borrow connection validation won't solve this problem you'd have to dive into the network setup. 如果使用具有借用连接验证的池库将无法解决此问题,则必须深入了解网络设置。 Perhaps between your application and the database there is a firewall which terminates any network connection eg by imposing a hard timeout. 也许在您的应用程序和数据库之间有一个防火墙可以终止任何网络连接,例如通过施加硬超时。 Normally this situation is solvable by setting a connection validation interval in the pool which is lower than the timeout imposed by the network. 通常,通过在池中设置低于网络施加的超时的连接验证间隔,可以解决这种情况。

Based in your problem description, I believe the connection it is dropped because it becomes iddle... 基于你的问题描述,我相信它被删除的连接,因为它变成了谜...

Try to append '?autoReconnect=true' to the end of your database's JDBC URL... and see if the problem does not happen more... 尝试将'?autoReconnect = true'附加到数据库的JDBC URL的末尾...并查看问题是否不会发生...

However, if you are not able to connect to the database even once, I suggest to check the following items: 但是,如果您甚至无法连接到数据库一次,我建议您检查以下项目:

  1. Do a ping command to your database IP from the server host 从服务器主机对数据库IP执行ping命令
  2. Do a telnet command to your database to see if you can reach the database port 对数据库执行telnet命令以查看是否可以访问数据库端口
  3. See if MySql does not have rules about which IPs can talk to it (I known that postgres have this feature, do not know if MySql does) 看看MySql是否没有关于哪些IP可以与它通信的规则(我知道postgres有这个功能,不知道MySql是否有)
  4. Check that MySql does not have something like drop iddle connections... 检查MySql是否有类似下拉连接的东西......
  5. Check your JDBC connection params 检查JDBC连接参数

The main culprit is wait_timeout . 主要罪魁祸首是wait_timeout Its default value is 28800 sec ie 8 hours. 其默认值为28800秒,即8小时。 From the doc: 来自doc:

The number of seconds the server waits for activity on a noninteractive connection before closing it. 服务器在关闭非交互式连接之前等待活动的秒数。

The error you are receiving is caused when the DB connection is idle(not performing any DB query) for wait_timeout secs. 当数据库连接空闲(不执行任何数据库查询) wait_timeout秒时,会导致您收到的错误。 After this time, MySQL drops the connection and you when your code makes any DB calls, it gets this error. 在此之后,MySQL会断开连接,当您的代码进行任何数据库调用时,它会收到此错误。

Increase this value(to say 1 day) and you can circumvent this problem. 增加此值(比如说1天)就可以解决这个问题。


However, to fix this issue, put autoReconnect=true in the DB connect string, like below: 但是,要解决此问题,请在DB连接字符串中输入autoReconnect=true ,如下所示:

jdbc:mysql://db_user:db_user@localhost/mydb?autoReconnect=true

This will cause the code to automatically reconnect the connection when the connection is dropped after wait_timeout secs. 这将导致代码在wait_timeout秒后删除连接时自动重新连接连接。

Well when we see log attached it says 好吧,当我们看到附加日志时,它说

The last packet successfully received from the server was 526 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.

Its not timeout issue for sure. 它肯定不是超时问题。 As idle wait time is around 500ms. 空闲等待时间约为500毫秒。

java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3008)


Wrapped by: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
    at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:115)

It looks like Database connection is getting blocked/interrupted. 看起来数据库连接被阻止/中断。

It can also most likely means that the database has restarted or the network connection to the database has been broken (eg a NAT connection has timed out) or may be firewall issue. 它也很可能意味着数据库已重新启动或与数据库的网络连接已断开(例如,NAT连接已超时)或可能是防火墙问题。

AutoReconnect is not recommended. 建议不要自动重新连接。 From MySQL here 来自MySQL 这里

Should the driver try to re-establish stale and/or dead connections? 驾驶员是否应该尝试重新建立陈旧和/或死亡的连接? If enabled the driver will throw an exception for a queries issued on a stale or dead connection, which belong to the current transaction, but will attempt reconnect before the next query issued on the connection in a new transaction. 如果启用,驱动程序将为在旧连接或死连接上发出的查询抛出异常,这些查询属于当前事务,但会在新事务中在连接上发出下一个查询之前尝试重新连接。 The use of this feature is not recommended, because it has side effects related to session state and data consistency when applications don't handle SQLExceptions properly, and is only designed to be used when you are unable to configure your application to handle SQLExceptions resulting from dead and stale connections properly. 建议不要使用此功能,因为当应用程序无法正确处理SQLExceptions时,它会产生与会话状态和数据一致性相关的副作用,并且仅在您无法配置应用程序以处理由此产生的SQLExceptions时使用。死和陈旧的连接正常。 Alternatively, as a last option, investigate setting the MySQL server variable "wait_timeout" to a high value, rather than the default of 8 hours. 或者,作为最后一个选项,研究将MySQL服务器变量“wait_timeout”设置为高值,而不是默认值为8小时。

Additional Suggestion: 补充建议:

to get rid of this warning : Establishing SSL connection without server's identity verification is 摆脱这个警告:在没有服务器身份验证的情况下建立SSL连接

use useSSL=false in Mysql Configuration 在Mysql配置中使用useSSL=false

eg: 例如:

jdbc:mysql://localhost:3306/Peoples?autoReconnect=true&useSSL=false

You can use 您可以使用

sessionFactory.isClosed();

to determine if the connection is still open. 确定连接是否仍处于打开状态。 Replace your getSessionFactory() method like this. 像这样替换你的getSessionFactory()方法。

public static SessionFactory getSessionFactory() {

    if (sessionFactory == null || sessionFactory.isClosed()) {
        sessionFactory = new Configuration()
                .configure()
                .addAnnotatedClass(Seller.class)
                .addAnnotatedClass(Book.class)
                .buildSessionFactory();
    }

    return sessionFactory;
}
   at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:989)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3556)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3456)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3897)

From your stacktrace it seems hibernate is not able to obtain connections from database as db server has gone away 从你的堆栈跟踪看来,当数据库服务器已经消失时,hibernate似乎无法从数据库获取连接

    // Check return value, if we get a java.io.EOFException, the server has gone away. We'll pass it on up the exception chain and let someone higher up
   // decide what to do (barf, reconnect, etc).

Check source here: 检查来源:
http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.36/com/mysql/jdbc/MysqlIO.java#3774 http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.36/com/mysql/jdbc/MysqlIO.java#3774

Possible explaination : 可能的解释:
The problem seems at database server side not in your code. 问题似乎在数据库服务器端而不在您的代码中。 You may need to tweak your mysql server settings and problem will be solved. 您可能需要调整您的mysql服务器设置,问题将得到解决。 The data you are sending is larger than the packet that is sent over the network to the database. 您发送的数据大于通过网络发送到数据库的数据包。

Causes and solutions : 原因和解决方案:
https://dev.mysql.com/doc/refman/5.7/en/gone-away.html https://dev.mysql.com/doc/refman/5.7/en/gone-away.html
http://befused.com/mysql/server-has-gone-away http://befused.com/mysql/server-has-gone-away

Other Solutions: 其他方案:
in my.cnf file of mysql add following settings 在mysql的my.cnf文件中添加以下设置

[mysqld]
max_allowed_packet=256M

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM