休眠连接超时
问题描述:
我们的服务器中的mysql连接有问题。 WebApp工作正常,但几个小时后,我们从与mysql的连接中得到一个错误。 我们认为hibernate Session有些问题。据我们所知,当hibernate尝试使用同一个会话时,mysql连接被关闭。 也许我们没有正确地关闭会话。休眠连接超时
我们使用Struts 2,并且定义了一个管理所有会话内容的拦截器。 下面是代码:
public class OSVStrutsInterceptors implements Interceptor {
private static SessionFactory sf;
@Override
public void destroy() {
try
{
sf.getCurrentSession().close();
}
catch (HibernateException ex)
{
throw new RuntimeException(ex);
}
}
@Override
public void init() {
}
@Override
public String intercept(ActionInvocation ai) throws Exception {
sf = HibernateUtil.getSessionFactory();
Session sesion=sf.getCurrentSession();
try {
sesion.beginTransaction();
}
catch (Exception ex) {
System.out.println(new Date()+" Sesion cerrada. Obtenemos una nueva");
sesion=sf.openSession();
}
String result=ai.invoke();
sesion.getTransaction().commit();
return result;
}
}
正如你所看到的,我们正在试图让currentSession,但如果是不可能的,我们打开一个新的会话。我们也关闭拦截器的destroy()方法的会话。
,但我们总能得到我们的服务器上此错误:
com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception:
** BEGIN NESTED EXCEPTION **
java.net.SocketException
MESSAGE: Broken pipe
STACKTRACE:
java.net.SocketException: Broken pipe
答
加入autoReconnect=true
不建议由MySQL(找不到参考)。相反,加上hibernate.cfg.xml
<!-- c3p0 -->
<property name="hibernate.c3p0.validate">true</property>
<property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">600</property>
<property name="hibernate.c3p0.timeout">1800</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.preferredTestQuery">SELECT 1;</property>
<property name="hibernate.c3p0.testConnectionOnCheckout">true</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
这些行,并增加这些库与您CLASSPATH
hibernate-c3p0-4.0.0.Final.jar
c3p0-0.9.1.jar (Not sure if this is neccessary)
答
通信链路故障情况可能的原因有很多,包括网络中断,路由器配置错误或其他网络问题。也有可能(虽然不太可能)你的连接只是超时。在任何情况下,您都可以尝试通过配置MySQL数据源来自动重新连接来解决问题。这样做的一种方式是通过指定的JDBC URL适当的属性:
url="jdbc:mysql://localhost:3306/mydb?autoReconnect=true
答
我用用org.apache.commons.dbcp.BasicDataSource一个自定义的ConnectionProvider。在这个类必须设置:
setValidationQuery("select 1");
setTestOnBorrow(true);
注:我缠上net.sf.log4jdbc.ConnectionSpy连接,但你可以做的不是
在hibernate.cfg<property name="hibernate.connection.provider_class">
example.DBCPConnectionProvider
</property>
public class DBCPConnectionProvider implements ConnectionProvider {
private static final long serialVersionUID = -4063997930726759172L;
private static final Logger log = Logger.getLogger(DBCPConnectionProvider.class);
static CustomDataSource ds;
static{
try {
ds = new CustomDataSource();
} catch (Exception e) {
log.error("", e);
}
}
@Override
public void closeConnection(Connection conn) throws SQLException {
conn.close();
}
@Override
public Connection getConnection() throws SQLException {
return ds.getConnection();
}
@Override
public boolean supportsAggressiveRelease() {
return true;
}
@Override
public boolean isUnwrappableAs(Class arg0) {
return false;
}
@Override
public <T> T unwrap(Class<T> arg0) {
return null;
}
}
public class CustomDataSource extends BasicDataSource{
private static final Logger log = Logger.getLogger(CustomDataSource.class);
public CustomDataSource(){
Properties props = HibernateConfiguration.getProperties();
setDriverClassName(props.getProperty("hibernate.connection.driver_class") );
setUsername( props.getProperty("hibernate.connection.username"));
setPassword(props.getProperty("hibernate.connection.password") );
setUrl(props.getProperty("hibernate.connection.url") );
setValidationQuery("select 1");
setTestOnBorrow(true);
}
@Override
public Connection getConnection() throws SQLException{
return new net.sf.log4jdbc.ConnectionSpy(super.getConnection());
}
}