我们使用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
请建议
答案 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>