How to set a default query timeout with JPA and Hibernate?

JPA 2 defines the javax.persistence.query.timeout hint to specify default timeout in milliseconds. Hibernate 3.5 (currently still in beta) will support this hint.

See also https://hibernate.atlassian.net/browse/HHH-4662


JDBC has this mechanism named Query Timeout, you can invoke setQueryTime method of java.sql.Statement object to enable this setting.

Hibernate cannot do this in unified way.

If your application retrive JDBC connection vi java.sql.DataSource, the question can be resolved easily.

we can create a DateSourceWrapper to proxy Connnection which do setQueryTimeout for every Statement it created.

The example code is easy to read, I use some spring util classes to help this.

public class QueryTimeoutConfiguredDataSource extends DelegatingDataSource {

private int queryTimeout;

public QueryTimeoutConfiguredDataSource(DataSource dataSource) {
    super(dataSource);
}

// override this method to proxy created connection
@Override
public Connection getConnection() throws SQLException {
    return proxyWithQueryTimeout(super.getConnection());
}

// override this method to proxy created connection
@Override
public Connection getConnection(String username, String password) throws SQLException {
    return proxyWithQueryTimeout(super.getConnection(username, password));
}

private Connection proxyWithQueryTimeout(final Connection connection) {
    return proxy(connection, new InvocationHandler() {
        //All the Statement instances are created here, we can do something
        //If the return is instance of Statement object, we set query timeout to it
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object object = method.invoke(connection, args);
            if (object instanceof Statement) {
                ((Statement) object).setQueryTimeout(queryTimeout);
            }
            return object;
        });
}

private Connection proxy(Connection connection, InvocationHandler invocationHandler) {
    return (Connection) Proxy.newProxyInstance(
            connection.getClass().getClassLoader(), 
            ClassUtils.getAllInterfaces(connection), 
            invocationHandler);
}

public void setQueryTimeout(int queryTimeout) {
    this.queryTimeout = queryTimeout;
}

}

Now we can use this QueryTimeoutConfiguredDataSource to wrapper your exists DataSource to set Query Timeout for every Statement transparently!

Spring config file:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource">
        <bean class="com.stackoverflow.QueryTimeoutConfiguredDataSource">
            <constructor-arg ref="dataSource"/>
            <property name="queryTimeout" value="1" />
        </bean>
    </property>
</bean>