2011-01-31 6 views
7

Mam aplikację, która ustanowi połączenie DB z MySQL i wykona zapytania. Czasami wywołanie metody DriverManager.getConnection() trwa 2 sekundy, a czasami zajmuje 30 sekund. Czy istnieje sposób kontrolowania tej metody do przekroczenia limitu czasu po 2 sekundach?Jak wymusić limit czasu dla wywołania metody DriverManager.getConnection()?

DriverManager.setLoginTimeout() wydaje się nie działać.

Rzeczywiście, jestem w stanie ustawić limit czasu dla statement.executeQuery() przez przespanie wątku dla mojej wartości limitu czasu i zamknięcie połączenia po przebudzeniu. Ale jest to połączenie, w którym nie mogłem ustawić limitu czasu.

Doceniam każdą pomoc.

+0

którego kierowca używasz i dla których dane bazy? –

+0

Używam sterownika mysql jdbc – ihavprobs

Odpowiedz

4

jeśli nie ma innych opcji, zawsze można po prostu wykonać połączenie w osobnym wątku, którego przerwanie/zignorować, jeśli nie zakończy w 2 sekundy.

EDIT Oto przykład tego, co myślałem:

public class Dummy extends Thread { 
private volatile Connection conn = null; 
@Override 
public void run() { 
    try { 
     this.conn = DriverManager.getConnection("foobar") ; 
    } catch (SQLException e) { 
     e.printStackTrace(); 
    } 
} 
static public Connection getConnection() { 
    Dummy d = new Dummy() ; 
    d.start() ; 
    try { 
     Thread.sleep(2000) ; 
    } catch (InterruptedException e) {} 
    return d.conn ; 
} 
} 

Następnie można po prostu wywołać metodę Dummy.getConnection statyczne() inne miejsca w kodzie. Jedną wadą jest to, że ta metoda zawsze będzie trwała 2 sekundy, ale zmiana jej na natychmiastowy powrót po zakończeniu wątku nie jest zbyt trudna.

+0

Jak przerwać wątek? Przerwanie wątku po 2 sekundach nie działa. – ihavprobs

+0

Cóż, jeśli uważasz, że musisz przerwać wątek, zawsze możesz po prostu wywołać metodę stop(), ale jest to nieaktualna metoda, więc najpierw przeczytaj ewentualne pułapki w dokumentach. Możesz także pozwolić mu kontynuować działanie, gdy zignorujesz to i ruszysz dalej. –

+0

dzięki, zatrzymanie wątku działa. – ihavprobs

0

Spróbuj ustawić wartość socketTimeout (czas w milisekundach) adresu URL połączenia lub puli połączeń (jeśli korzystasz z puli). Uważaj, aby ta wartość nie była zbyt niska lub nadpisała wartość limitu czasu instrukcji.

try { 
    this.conn = DriverManager.getConnection("url?socketTimeout=2000") ; 
} catch (SQLException e) { 
    e.printStackTrace(); 
} 

lub

<jdbc-connection-pool 
        connection-validation-method="table" 
        fail-all-connections="true" 
        idle-timeout-in-seconds="300" 
        is-connection-validation-required="true" 
        statement-timeout-in-seconds="2" 
        validation-table-name="dual" 
        ..... > 
    <property name="databaseName" value="...."/> 
    <property name="serverName" value="....."/> 
    <property name="User" value="....."/> 
    <property name="Password" value="......."/> 
    <property name="URL" value="jdbc:mysql://...../...."/> 
    <property name="driverClass" value="...."/> 
    <property name="socketTimeout" value="2000"/> 
</jdbc-connection-pool> 

Ustawienie to naprawić problem limitu czasu dla mnie.

2

Możesz użyć interfejsu ExecutorService z Java. Poniżej znajduje się próbka tego, co musisz zrobić.

Future<Boolean> future = executor.submit(YOUR_METHOD); 
future.get(TIMEOUT_YOU_NEED, TimeUnit.SECONDS); 
0

Dziękuję za kodboltę, nie wiem, czy to najlepsze rozwiązanie, ale działa to dla mnie. 10-sekundowy limit czasu.

public class Dummy extends Thread { 
      private volatile java.sql.Connection conn = null; 
      private boolean sleep = true; 
      @Override 
      public void run() { 
       try { 

        String driver = "net.sourceforge.jtds.jdbc.Driver"; 
        Class.forName(driver).newInstance();      
        //timeout 
        DriverManager.setLoginTimeout(10); 
        this.conn = DriverManager.getConnection(url, user, pwd); 
        sleep = false; 
       } catch (Exception e) {} 
      } 
      public java.sql.Connection getConnection() { 
       Dummy d = new Dummy() ; 
       d.start() ; 
       try { 
        for(int i=1; i<=10; i++) { 
         //Wait 1 second 
         if (d.sleep){ 
          Thread.sleep(1000); 
         } 
        } 
       } catch (InterruptedException e) {} 
       return d.conn ; 
      } 
      } 

i wezwanie:

Dummy a = new Dummy(); 
connection = a.getConnection(); 
if (connection != null) {.... 
+0

Wysłany przez [anonimowy użytkownik] (http://stackoverflow.com/review/suggested-edits/2889625): 'Jeśli uczynisz metodę getConnection() statyczną, nie musisz tworzyć obiektu, który nigdy nie jest używany. Idąc dalej, możesz stworzyć nazwę klasy sterownika, adres URL, nazwę użytkownika i argumenty haseł do getConnection() i mieć coś całkiem ogólnego celu. " – gunr2171

0

I rozszerzony na odpowiedzi przez CodeBolt i anpadia złożyć następujące pełną klasę. Ma tylko jedną statyczną metodę, która akceptuje wszystkie potrzebne parametry połączenia, w tym czas trwania limitu czasu. Dodatkowo, metoda wil rzuci również wyjątek SQLException i ClassNotFoundException, jeśli wystąpią.

Zastosowanie:

String connectionUrl = "..."; 
String user = "..."; 
String password = "..."; 
String driver = "org.postgresql.Driver"; // for example 

int timeoutInSeconds = 5; 

Connection myConnection = 
    ConnectWithTimeout.getConnection(connectionUrl, user, password, driver, timeoutInSeconds); 

Poniżej jest realizacja:

import java.sql.DriverManager; 
import java.sql.Connection; 
import java.sql.SQLException; 


public class ConnectWithTimeout extends Thread { 

    private static String _url; 
    private static String _user; 
    private static String _password; 
    private static String _driver; 

    private static volatile Connection _connection = null; 
    private static volatile boolean _sleep = true; 
    private static volatile SQLException _sqlException = null; 
    private static volatile ClassNotFoundException _classNotFoundException = null; 

    @Override 
    public void run() { 
     try { 
      Class.forName(_driver); 
      _connection = DriverManager.getConnection(_url, _user, _password); 
     } 
     catch (SQLException ex) { 
      _sqlException = ex; 
     } 
     catch (ClassNotFoundException ex) { 
      _classNotFoundException = ex; 
     } 
     _sleep = false; 
    } 

    public static Connection getConnection(String url, 
              String user, 
              String password, 
              String driver, 
              int timeoutInSeconds) 
     throws SQLException, ClassNotFoundException { 

     checkStringOrThrow(url,  "url"); 
     checkStringOrThrow(user,  "user"); 
     checkStringOrThrow(password, "password"); 
     checkStringOrThrow(driver, "driver"); 

     if (timeoutInSeconds < 1) { 
      throw new IllegalArgumentException(
       "timeoutInSeconds must be positive"); 
     } 

     _url = url; 
     _user = user; 
     _password = password; 
     _driver = driver; 

     ConnectWithTimeout conn = new ConnectWithTimeout(); 
     conn.start(); 

     try { 
      for (int i = 0; i < timeoutInSeconds; i++) { 
       if (_sleep) { 
        Thread.sleep(1000); 
       } 
      } 
     } 
     catch (InterruptedException ex) { 
     } 

     if (_sqlException != null) { 
      throw _sqlException; 
     } 

     if (_classNotFoundException != null) { 
      throw _classNotFoundException; 
     } 

     return _connection; 
    } 

    private static void checkStringOrThrow(String variable, String variableName) { 
     if (variable == null || variable.length() == 0) { 
      throw new IllegalArgumentException(
       "String is null or empty: " + variableName); 
     } 
    } 
}