2010-01-20 13 views
7

Ich mache einige große Abfragen auf meiner Datenbank mit Hibernate und ich manchmal Timeouts getroffen. Ich möchte vermeiden, das Timeout manuell auf jedem Query oder Criteria zu setzen.Hibernate: Standard-Abfrage-Timeout festlegen?

Gibt es eine Eigenschaft, die ich meiner AnnotationConfiguration geben kann, die einen akzeptablen Standard für alle von mir ausgeführten Abfragen festlegen würde?

Wenn nicht, wie kann ich einen Standard-Timeout-Wert für Hibernate-Abfragen festlegen?

+0

Verwenden Sie einen Verbindungspool. – Bozho

+0

Yup, mit C3PO – malaverdiere

Antwort

5

JPA 2 definiert den javax.persistence.query.timeout hint zurückkehr Standard-Timeout in Millisekunden angegeben werden. Hibernate 3.5 (derzeit noch in der Betaversion) wird diesen Hinweis unterstützen.

siehe Query Timeout genannt http://opensource.atlassian.com/projects/hibernate/browse/HHH-4662

+0

Ich bin nicht allzu aufgeregt über eine Beta-Version ... Wenn ich mir die Seite anschaue, sehe ich kein erwartetes Veröffentlichungsdatum. Weißt du, wann sie es veröffentlichen wollen? – malaverdiere

+0

Die CR-Veröffentlichung ist nur ein paar Wochen entfernt und ich würde denken, dass 3.5 kurz darauf folgen wird. Die Einhaltung der JPA 2 steht auf der Prioritätenliste ganz oben, daher besteht kein Risiko, dass das Problem unter die Tabelle fällt. – Hardy

+0

Dieses Timeout funktioniert in diesem Fall, wenn sich die Abfrage im Deadlock befindet? – Laszlo

1

Hier sind ein paar Möglichkeiten:

  • Verwenden Sie eine Fabrik oder eine Methode der Basisklasse alle Abfragen zu erstellen und das Timeout, bevor die Abfrage Objekt
  • Ihre eigene Version von org.hibernate.loader erstellen zurück. Loader und setzen Sie das Timeout in doQuery
  • Verwenden Sie AOP, z Spring, um einen Proxy für Session zurückzugeben; füge Beratung, dass das Verfahren Create wickelt und setzt das Timeout auf dem Objektabfrage, bevor es
+0

Ich dachte an die erste Option, die Sie zuerst gab, aber ich dachte "sicherlich, Hibernate bietet eine Möglichkeit, dies zu vermeiden!" Über den Loader, ich bin nicht allzu aufgeregt über das Erstellen eines neuen in vollem Umfang. Aber ich dachte, dass ich vielleicht' BasicLoader' erweitern kann. Die Sache ist, ich sehe keine 'doQuery' in dieser API: https://www.hibernate.org/hib_docs/v3/api/org/hibernate/loader/Loader.html Also, ich müsste überschreiben, welche Methoden? Ich vermute 'doList',' getResultSet' "prepareQueryStatement" und "scroll". Habe ich recht? – malaverdiere

+0

Ich könnte mich irren, aber ich glaube nicht, dass Hibernate Sie so in den Loader einbinden kann. Ich habe den Hibernate-Loader vom Quellcode in mein Projekt kopiert, mit dem gleichen Paket wie Hibernate Da meine Klassen im Klassenpfad dem Hibernate voraus sind, wird meins verwendet. Der einzige Nachteil ist, dass Sie dies jedes Mal tun müssen, wenn Sie Hibernate aktualisieren, aber wenn Sie das PreparedStatement-Objekt vor dem qu Sie können setQueryTimeout aufrufen, daher ist preparateQueryStatement die beste Wahl. –

3

JDBC diesen Mechanismus hat auch können Sie setQueryTime Methode java.sql.Statement Objekt aufrufen, diese Einstellung zu aktivieren.

Hibernate kann dies nicht in einheitlicher Weise tun.

Wenn Ihre Anwendung die JDBC-Verbindung vi java.sql.DataSource reaktiviert, kann die Frage leicht gelöst werden.

können wir einen DateSourceWrapper Proxy Connnection erstellen, die für jede erstellte Anweisung SetQueryTimeout setzen.

Der Beispielcode ist leicht zu lesen, ich benutze einige Spring-Util-Klassen, um dies zu unterstützen.

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; 
} 

}

Jetzt können wir diese QueryTimeoutConfiguredDataSource benutzen, um Ihre Wrapper existiert Datasource Abfrage-Timeout transparent für jede Anweisung zu setzen!

Frühling Konfigurationsdatei:

<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> 
0

Für globale Timeout-Werte auf Abfrageebene einstellen - die unten an Konfigurationsdatei hinzufügen.

Zum Festlegen globaler Zeitüberschreitungswerte auf Transaktionsebene (INSERT/UPDATE) - Fügen Sie die folgende Konfigurationsdatei hinzu.

<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> 
+0

Ich bekomme einen Fehler, wenn ich maven build, habe ich auf die Abfrage hier können Sie helfen: http://StackOverflow.com/Questions/41613160/default-query-timeout-is-causing-exception-in- Integrationstest – Pavanraotk