2011-01-31 15 views
7

Tengo una aplicación que establecerá una conexión de base de datos con MySQL y ejecutará consultas. A veces, la llamada al método DriverManager.getConnection() demora 2 segundos y a veces demora 30 segundos. ¿Hay alguna manera de controlar este método para que se agote el tiempo después de 2 segundos?Cómo forzar el tiempo de espera para la llamada al método DriverManager.getConnection()?

DriverManager.setLoginTimeout() parece que no funciona.

En realidad, puedo configurar el tiempo de espera para statement.executeQuery() durmiendo el hilo de mi valor de tiempo de espera y cerrando la conexión después de la activación. Pero es la parte del establecimiento de conexión donde realmente no pude establecer el tiempo de espera.

Agradecería cualquier ayuda.

+0

el controlador que está utilizando y para el que la base de datos? –

+0

Uso el controlador jdbc mysql – ihavprobs

Respuesta

4

Si no hay otras opciones, siempre se puede simplemente ejecutar la llamada en un hilo separado, que aborta/ignore si no termina en 2 segundos

EDITAR He aquí un ejemplo de lo que estaba pensando:

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

a continuación, puedes llamar al método Dummy.getConnection estática() otros lugares en el código. Una desventaja es que este método siempre tardará 2 segundos, pero cambiarlo para que vuelva inmediatamente cuando termine el hilo no es demasiado difícil.

+0

¿Cómo abortar el hilo? Interrumpir el hilo después de 2 segundos no funciona. – ihavprobs

+0

Bueno, si crees que tienes que abortar el hilo, siempre puedes llamar a stop(), pero ese es un método en desuso, así que lee primero cualquier posible inconveniente en los documentos. También puede dejar que continúe ejecutándose mientras lo ignora y continúa. –

+0

gracias, detener el hilo funciona. – ihavprobs

0

Intente configurar el socketTimeout (Tiempo en milisegundos) en la URL de conexión o en el grupo de conexiones (si está utilizando la agrupación). Tenga cuidado de no establecer este valor demasiado bajo o sobrescribirá el valor de tiempo de espera de la declaración.

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

o

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

Ajuste de que esto esté arreglado el problema de tiempo de espera para mí.

2

Puede usar la interfaz ExecutorService de Java. A continuación hay una muestra de lo que debe hacer.

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

Gracias a codebolt, no sé si es la mejor solución, pero esto funciona para mí. Un tiempo de espera de 10 segundos.

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

Y la llamada:

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

Publicado por un [usuario anónimo] (http://stackoverflow.com/review/suggested-edits/2889625): 'Si hace que el método getConnection() sea estático, no tiene que crear el objeto a que nunca es usado. Yendo más lejos, podría hacer que el nombre de la clase del controlador, la URL, el nombre de usuario y los argumentos de las contraseñas lleguen a getConnection() y que tengan un propósito bastante general. – gunr2171

0

amplié en las respuestas por CodeBolt y anpadia hacer la siguiente clase completa. Solo tiene un método estático que acepta todos los parámetros de conexión necesarios, incluida la duración del tiempo de espera. Además, el método también arrojará SQLException y ClassNotFoundException si se producen.

Uso:

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

A continuación se muestra la ejecución:

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); 
     } 
    } 
} 
Cuestiones relacionadas