从服务器成功收到的最后一个数据包是43417秒前

时间:2017-07-15 05:34:02

标签: mysql spring hibernate

我们使用Spring 4.2.5,Hibernate 4.1.4,MYSql来构建REST服务。我们面临着非常奇怪的问题,并且无法理解正在发生的事情并且低于错误:

从服务器成功收到的最后一个数据包是43417秒前。成功发送到服务器的最后一个数据包是43417秒前,这比服务器配置的值“wait_timeout'”更长。您应该考虑在应用程序中使用之前过期和/或测试连接有效性,增加服务器配置的客户端超时值,或者使用Connector / J连接属性" autoReconnect = true'避免这个问题。

为了获得数据库连接,我们使用基于java的配置,如下所示:

    @Configuration
    @EnableTransactionManagement
    @ComponentScan({ "api.configuration" })

public class HibernateConfiguration {
    @Autowired
    private Environment environment;

    private static final Logger logger = LoggerFactory.getLogger(HibernateConfiguration.class);
    @Bean
    public LocalSessionFactoryBean sessionFactory() throws PropertyVetoException {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "api.domain" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
     }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test?autoReconnect=true");
        dataSource.setUsername("test"); 
        dataSource.setPassword("test");
        return dataSource;
    }


    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.format_sql", "true");
        properties.put("hibernate.hbm2ddl.auto", "update");
        properties.put("connection.autoReconnect",  "true");
        properties.put("connection.autoReconnectForPools","true");
        properties.put("connection.is-connection-validation-required", "true");

        return properties;        
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws PropertyVetoException {
       LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
       em.setDataSource(dataSource());
       em.setPackagesToScan(new String[] { "api.domain" });

       JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
       em.setJpaVendorAdapter(vendorAdapter);
       em.setJpaProperties(hibernateProperties());

       return em;
    }

    @Bean
    public PlatformTransactionManager transactionManager() throws PropertyVetoException{
       JpaTransactionManager transactionManager = new JpaTransactionManager();
       transactionManager.setEntityManagerFactory(entityManagerFactory().getObject() );
       return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
       return new PersistenceExceptionTranslationPostProcessor();
    }
}

已经google了一下,发现我们可以通过添加以下两个属性来解决这个问题:

<property name=”validationQuery” value=”SELECT 1″ />

<property name=”testOnBorrow” value=”true” />

由于我们使用的是java配置而不是基于XML,因此我们不知道要为java类中的 validationQuery testOnBorrow 添加的确切属性名称有 hibernate.show_sql

请建议

1 个答案:

答案 0 :(得分:1)

让我们先了解这个问题。 java.sql.Connection是一个Java对象,代表一些MySQL服务器连接。这是通过TCP发生的客户端 - 服务器通信。如果服务器连接中断或TCP连接中断,客户端不知道这一点,那么Java对象仍然存在,但它无法再与服务器通信。在您的情况下,如果MySQL服务器空闲一段时间(默认情况下为8小时),则MySQL服务器会终止过时连接。

如果您创建一个裸驱动程序连接,这种情况将非常罕见 - 这些连接在短时间使用后创建并关闭。在你的例子中,事情非常混乱 - 你使用SessionFactory和EntityManagerFactory,看起来你使用裸连接(并且很难通过裸连接获得此错误),所以我不会对它发表评论。

您找到的选项不适用于Hibernate。它们用于生产就绪数据库池之一(我假设为Tomcat JDBC Pool)。因此,您应该使用该池(或其他类似C3P0)并将其配置为定期检查连接 - 这样,从MySQL Server的角度来看,连接不会过时。以下是C3P0配置的示例:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="jdbcUrl" value="jdbc:h2:mem:qalatraining;DB_CLOSE_DELAY=-1"/>
    <property name="driverClass" value="org.h2.Driver"/>
    <property name="user" value="sa"/>
    <property name="password" value=""/>
    <property name="maxPoolSize" value="10"/>
    <property name="idleConnectionTestPeriod" value="3600"/>
    <property name="testConnectionOnCheckin" value="true"/>
</bean>

现在你应该把这个DataSource传递给Hibernate:

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
</bean>

配置数据库池还有很多,您可以找到详细信息here和工作示例here