Java 如何使用JPA和Hibernate设置默认查询超时?

Java 如何使用JPA和Hibernate设置默认查询超时?,java,hibernate,jpa,configuration,timeout,Java,Hibernate,Jpa,Configuration,Timeout,我正在用Hibernate对我的数据库进行一些大的查询,有时会超时。我希望避免在每个查询或条件上手动设置超时 我是否可以为我的Hibernate配置提供任何属性,为我运行的所有查询设置可接受的默认值 如果没有,如何设置Hibernate查询的默认超时值?以下是几种方法: 使用工厂或基类方法创建所有查询,并在返回查询对象之前设置超时 创建自己的org.hibernate.loader.loader版本,并在doQuery中设置超时 使用AOP(例如Spring)返回会话的代理;在返回查询对象之前

我正在用Hibernate对我的数据库进行一些大的查询,有时会超时。我希望避免在每个
查询
条件
上手动设置超时

我是否可以为我的Hibernate配置提供任何属性,为我运行的所有查询设置可接受的默认值

如果没有,如何设置Hibernate查询的默认超时值?

以下是几种方法:

  • 使用工厂或基类方法创建所有查询,并在返回查询对象之前设置超时
  • 创建自己的org.hibernate.loader.loader版本,并在doQuery中设置超时
  • 使用AOP(例如Spring)返回会话的代理;在返回查询对象之前,向其添加包装createQuery方法并设置查询对象超时的建议
JPA2定义javax.persistence.query.timeout提示,以毫秒为单位指定默认超时。Hibernate3.5(目前仍处于测试阶段)将支持此提示


另请参见

JDBC有一个名为查询超时的机制,您可以调用java.sql.Statement对象的setQueryTime方法来启用此设置

Hibernate不能以统一的方式完成这项工作

如果您的应用程序检索JDBC connection vi java.sql.DataSource,那么这个问题很容易解决

我们可以为代理连接创建一个DateSourceWrapper,它为它创建的每个语句设置QueryTimeout

示例代码很容易阅读,我使用了一些SpringUtil类来帮助实现这一点

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包装您现有的数据源,以透明地为每个语句设置查询超时

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>

用于在查询级别设置全局超时值-将以下内容添加到配置文件中

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
    <property name="queryTimeout" value="60"></property>
</bean>
<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>


要在事务(插入/更新)级别设置全局超时值,请将以下内容添加到配置文件中

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
    <property name="queryTimeout" value="60"></property>
</bean>
<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>

是的,你可以这样做

正如我在中所解释的,您只需将JPA查询提示作为全局属性传递:

<property
    name="javax.persistence.query.timeout"
    value="1000"
/>

有关为Hibernate查询设置超时时间间隔的详细信息,请查看。

您使用的是连接池吗。我本想执行您最初给出的第一个选项,但我认为“当然,Hibernate提供了一种避免这种情况的方法!”关于加载程序,我对完全创建一个新的加载程序不太感兴趣。但是我想也许我可以扩展
BasicLoader
。问题是,我在该API中没有看到
doQuery
:因此,我必须重写哪些方法?我猜是
doList
getResultSet
prepareQueryStatement
scroll
。我是对的吗?我可能错了,但我不认为Hibernate可以让你通过这种方式连接到加载程序。我使用与hibernate相同的包将hibernate加载程序从源代码复制到我的项目中;因为我的类在类路径中位于Hibernate之前,所以我的类会被使用。唯一的缺点是每次升级Hibernate时都必须这样做。但是,如果您可以在查询运行之前访问PreparedStatement对象,则可以调用setQueryTimeout,因此prepareQueryStatement可能是您的最佳选择。我对构建beta版不太感兴趣。。。看看这个网站,我看不到预期的发布日期。你知道他们计划什么时候发布吗?CR发布只有几个星期了,我想3.5不久就会发布。JPA 2合规性在优先级列表中处于较高位置,因此没有问题被列入表中的风险。在这种情况下,当查询处于死锁状态时,此超时有效?我在执行maven构建时出错,我已在此处指向查询。您能帮到我吗: