Hibernate失去连接

时间:2018-03-14 15:12:39

标签: java hibernate dao

我正在使用hibernate连接我的mysql数据库并执行事务。

我在整个应用程序中使用单个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)

这是我创建SessionFactory的方式:

public static SessionFactory getSessionFactory() {

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

    return sessionFactory;
}

这是我在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();
        }

    }
}

我的应用程序是一个爬虫从Web抓取一个书对象,并通过上面的保存功能将对象保存到数据库。我无法找到这个例外背后的原因。

在命令控制台上,我可以看到连接在丢失后重新建立,在这里:

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.

我将不胜感激。

6 个答案:

答案 0 :(得分:10)

由于您的问题涉及网络,因此最好的想法可能是在您的设置中添加JDBC连接池。这将确保在您的应用程序运行时连接不会过时,例如由于数据库服务器端超时。

HikariCP是我最喜欢的游泳池,因为它设置合理的默认值,例如借用连接验证,无法禁用。由于您使用的是Hibernate,因此HikariCP会显示如何设置所有内容on their wiki page。但是,正确的设置可能取决于您使用的其他库,例如Spring Boot中共享java.sql.DataSource bean。

您可以使用其他池库,但在走这条路线之前请花几分钟时间阅读:

如果使用具有借用连接验证的池库,则无法解决此问题,您必须深入了解网络设置。也许在您的应用程序和数据库之间有一个防火墙可以终止任何网络连接,例如:通过施加硬超时。通常,通过在池中设置一个低于网络强制超时的连接验证间隔,可以解决这种情况。

答案 1 :(得分:4)

根据您的问题描述,我相信它被删除的连接因为它变成了谜语......

尝试附加'?autoReconnect = true'到数据库的JDBC URL的末尾......并查看问题是否不会发生......

但是,如果您连一次都无法连接到数据库,我建议您检查以下项目:

  1. 从服务器主机
  2. 对数据库IP执行ping命令
  3. 对数据库执行telnet命令以查看是否可以访问数据库端口
  4. 看看MySql是否没有关于哪些IP可以与之通信的规则(我知道postgres有这个功能,不知道MySql是否有)
  5. 检查MySql是否有类似下拉连接...
  6. 的内容
  7. 检查JDBC连接参数

答案 2 :(得分:3)

主要罪魁祸首是wait_timeout。其默认值为28800秒,即8小时。来自doc:

  

服务器在关闭非交互式连接之前等待活动的秒数。

当数据库连接空闲(不执行任何数据库查询)wait_timeout秒时,会导致您收到的错误。在此之后,MySQL会断开连接,当您的代码进行任何数据库调用时,它会收到此错误。

增加此值(比如说1天),您就可以解决这个问题。

但是,要解决此问题,请将autoReconnect=true放入数据库连接字符串中,如下所示:

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

这会导致代码在wait_timeout秒后删除连接时自动重新连接连接。

答案 3 :(得分:3)

当我们看到附加日志时,它说

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

肯定不是超时问题。空闲等待时间约为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)

看起来数据库连接被阻止/中断。

它也很可能意味着数据库已重新启动或与数据库的网络连接已断开(例如,NAT连接已超时)或可能是防火墙问题。

建议不要使用AutoReconnect。来自MySQL here

  

驾驶员是否应该尝试重新建立陈旧和/或死亡连接?   如果启用,驱动程序将为发出的查询抛出异常   陈旧或死亡的连接,属于当前交易,   但会在下一个查询发出之前尝试重新连接   新交易中的连接。使用此功能不是   建议,因为它有与会话状态和。相关的副作用   应用程序不处理SQLExceptions时的数据一致性   正确,并且只在您无法使用时使用   配置您的应用程序以处理由死亡导致的SQLExceptions   和陈旧的连接正确。或者,作为最后一种选择,   调查将MySQL服务器变量“wait_timeout”设置为高   值,而不是默认的8小时。

补充建议:

去除此警告:在没有服务器身份验证的情况下建立SSL连接

在Mysql配置中使用useSSL=false

例如:

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

答案 4 :(得分:2)

您可以使用

sessionFactory.isClosed();

确定连接是否仍处于打开状态。像这样替换你的getSessionFactory()方法。

public static SessionFactory getSessionFactory() {

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

    return sessionFactory;
}

答案 5 :(得分:1)

   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)

从你的堆栈跟踪看来,当数据库服务器已经消失时,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).

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

可能的解释:
问题似乎在数据库服务器端而不在您的代码中。您可能需要调整您的mysql服务器设置,问题将得到解决。您发送的数据大于通过网络发送到数据库的数据包。

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

其他解决方案:
在mysql的my.cnf文件中添加以下设置

[mysqld]
max_allowed_packet=256M