簡體   English   中英

Hibernate失去連接

[英]Hibernate loses connection

我正在使用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.

我將不勝感激任何幫助。

由於您的問題涉及網絡,因此最好的想法可能是在您的設置中添加JDBC連接池。 這將確保在應用程序運行時連接不會過時,例如由於數據庫服務器端超時。

HikariCP是迄今為止我最喜歡的池,因為它設置合理的默認值,例如無法禁用的on- borrow連接驗證。 由於您使用的是Hibernate,HikariCP會顯示如何在其Wiki頁面上設置所有內容。 但是,正確的設置可能取決於您正在使用的其他庫,例如Spring Boot中的共享java.sql.DataSource bean。

您可以使用其他池庫,但在走這條路線之前請花幾分鍾時間閱讀:

如果使用具有借用連接驗證的池庫將無法解決此問題,則必須深入了解網絡設置。 也許在您的應用程序和數據庫之間有一個防火牆可以終止任何網絡連接,例如通過施加硬超時。 通常,通過在池中設置低於網絡施加的超時的連接驗證間隔,可以解決這種情況。

基於你的問題描述,我相信它被刪除的連接,因為它變成了謎...

嘗試將'?autoReconnect = true'附加到數據庫的JDBC URL的末尾...並查看問題是否不會發生...

但是,如果您甚至無法連接到數據庫一次,我建議您檢查以下項目:

  1. 從服務器主機對數據庫IP執行ping命令
  2. 對數據庫執行telnet命令以查看是否可以訪問數據庫端口
  3. 看看MySql是否沒有關於哪些IP可以與它通信的規則(我知道postgres有這個功能,不知道MySql是否有)
  4. 檢查MySql是否有類似下拉連接的東西......
  5. 檢查JDBC連接參數

主要罪魁禍首是wait_timeout 其默認值為28800秒,即8小時。 來自doc:

服務器在關閉非交互式連接之前等待活動的秒數。

當數據庫連接空閑(不執行任何數據庫查詢) wait_timeout秒時,會導致您收到的錯誤。 在此之后,MySQL會斷開連接,當您的代碼進行任何數據庫調用時,它會收到此錯誤。

增加此值(比如說1天)就可以解決這個問題。


但是,要解決此問題,請在DB連接字符串中輸入autoReconnect=true ,如下所示:

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

這將導致代碼在wait_timeout秒后刪除連接時自動重新連接連接。

好吧,當我們看到附加日志時,它說

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連接已超時)或可能是防火牆問題。

建議不要自動重新連接。 來自MySQL 這里

駕駛員是否應該嘗試重新建立陳舊和/或死亡的連接? 如果啟用,驅動程序將為在舊連接或死連接上發出的查詢拋出異常,這些查詢屬於當前事務,但會在新事務中在連接上發出下一個查詢之前嘗試重新連接。 建議不要使用此功能,因為當應用程序無法正確處理SQLExceptions時,它會產生與會話狀態和數據一致性相關的副作用,並且僅在您無法配置應用程序以處理由此產生的SQLExceptions時使用。死和陳舊的連接正常。 或者,作為最后一個選項,研究將MySQL服務器變量“wait_timeout”設置為高值,而不是默認值為8小時。

補充建議:

擺脫這個警告:在沒有服務器身份驗證的情況下建立SSL連接

在Mysql配置中使用useSSL=false

例如:

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

您可以使用

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;
}
   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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM