我正在使用Hibernate对我的数据库进行一些大查询,我有时会遇到超时。我想避免在每个Query
或Criteria
上手动设置超时。
我可以提供给AnnotationConfiguration
的任何属性,为我运行的所有查询设置一个可接受的默认值吗?
如果没有,我如何在Hibernate查询中设置默认超时值?
答案 0 :(得分:9)
JPA 2定义 javax.persistence.query.timeout 提示以指定默认超时(以毫秒为单位)。 Hibernate 3.5(目前仍处于测试阶段)将支持此提示。
答案 1 :(得分:4)
JDBC有这个名为Query Timeout的机制,你可以调用java.sql.Statement对象的setQueryTime方法来启用这个设置。
Hibernate无法以统一的方式执行此操作。
如果您的应用程序通过vi java.sql.DataSource重新连接JDBC连接,则可以轻松解决该问题。
我们可以创建一个DateSourceWrapper来代理Connnection,它为它创建的每个Statement执行setQueryTimeout。
示例代码易于阅读,我使用一些spring util类来帮助解决这个问题。
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;
}
}
现在我们可以使用这个QueryTimeoutConfiguredDataSource来包装您的存在DataSource,以便透明地为每个Statement设置Query Timeout!
Spring配置文件:
<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>
答案 2 :(得分:1)
以下是一些方法:
答案 3 :(得分:0)
用于在查询级别设置全局超时值 - 将以下内容添加到配置文件。
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
<property name="queryTimeout" value="60"></property>
</bean>
用于在事务(INSERT / UPDATE)级别设置全局超时值 - 将以下内容添加到配置文件中。
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
<property name="dataSource" ref="dataSource" />
<property name="defaultTimeout" value="60" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
答案 4 :(得分:0)
是的,你可以做到。
正如我在this article中所解释的,您要做的就是将JPA查询提示作为全局属性传递:
<property
name="javax.persistence.query.timeout"
value="1000"
/>
现在,当执行将在1秒后超时的JPQL查询时:
List<Post> posts = entityManager
.createQuery(
"select p " +
"from Post p " +
"where function('1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(2) ) --',) is ''", Post.class)
.getResultList();
Hibernate将抛出查询超时异常:
SELECT p.id AS id1_0_,
p.title AS title2_0_
FROM post p
WHERE 1 >= ALL (
SELECT 1
FROM pg_locks, pg_sleep(2)
) --()=''
-- SQL Error: 0, SQLState: 57014
-- ERROR: canceling statement due to user request
有关为Hibernate查询设置超时间隔的更多详细信息,请查看this article。