Как установить тайм-аут для вызова метода DriverManager.getConnection()?

У меня есть приложение, которое будет устанавливать соединение с БД с MySQL и выполнять запросы. Иногда вызов метода DriverManager.getConnection() занимает 2 секунды, а иногда 30 секунд. Есть ли способ контролировать время ожидания этого метода через 2 секунды?

DriverManager.setLoginTimeout() не работает.

На самом деле, я могу установить тайм-аут для statement.executeQuery(), приостановив поток для моего значения тайм-аута и закрыв соединение после пробуждения. Но это часть установления соединения, где я не мог установить тайм-аут.

Был бы признателен за любую помощь.


person ihavprobs    schedule 31.01.2011    source источник
comment
какой драйвер вы используете и для какой базы данных?   -  person Aravind Yarram    schedule 31.01.2011


Ответы (6)


Если других вариантов нет, вы всегда можете просто выполнить вызов в отдельном потоке, который вы прервете/проигнорируете, если он не завершится через 2 секунды.

ИЗМЕНИТЬ Вот пример того, о чем я думал:

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

Затем вы можете просто вызвать статический метод Dummy.getConnection() в других местах вашего кода. Одним из недостатков является то, что этот метод всегда будет занимать 2 секунды, но изменить его, чтобы он возвращался немедленно после завершения потока, не так уж сложно.

person Rune Aamodt    schedule 31.01.2011
comment
Как прервать ветку? Прерывание потока через 2 секунды не работает. - person ihavprobs; 31.01.2011
comment
Что ж, если вы считаете, что вам нужно прервать поток, вы всегда можете просто вызвать для него stop(), но это устаревший метод, поэтому сначала ознакомьтесь с любыми подводными камнями в документации. Вы также можете просто позволить ему продолжать работать, игнорируя его и двигаясь дальше. - person Rune Aamodt; 31.01.2011
comment
Извините, но thread.stop() говорит, что если целевой поток ожидает в течение длительного времени (например, в переменной условия), следует использовать метод прерывания, чтобы прервать ожидание. Но в моем случае прерывание() не помогает. Могу ли я узнать причину? - person ihavprobs; 31.01.2011

Спасибо codebolt, я не знаю, лучшее ли это решение, но это работает для меня. Тайм-аут 10 секунд.

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

И звонок:

Dummy a = new Dummy();
connection = a.getConnection();
if (connection != null) {....
person anpadia    schedule 17.07.2013
comment
Размещено анонимным пользователем: If you make the getConnection() method static, you don't have to create object a which is never used. Going further, you could make the driver class name, URL, user name, and passwords arguments to getConnection() and have something quite general purpose. - person gunr2171; 09.09.2013

Вы можете использовать интерфейс ExecutorService из Java. Ниже приведен пример того, что вам нужно сделать.

Future<Boolean> future = executor.submit(YOUR_METHOD);
future.get(TIMEOUT_YOU_NEED, TimeUnit.SECONDS);
person bestro    schedule 03.07.2013

Попробуйте установить socketTimeout (время в миллисекундах) в URL-адресе соединения или в пуле соединений (если вы используете пул). Следите за тем, чтобы это значение не было слишком низким, иначе оно перезапишет значение тайм-аута оператора.

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

or

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

Установка этого устранила проблему тайм-аута для меня.

person SteveGreenslade    schedule 13.05.2013

Я расширил ответы CodeBolt и anpadia, чтобы создать следующий полный класс. Он имеет только один статический метод, который принимает все необходимые параметры подключения, включая время ожидания. Кроме того, метод также выдает исключения SQLException и ClassNotFoundException, если они возникают.

Использование:

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

Ниже приведена реализация:

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);
        }
    }
}
person stackoverflowuser2010    schedule 01.05.2015

Вот пример использования:

http://www.javadocexamples.com/java/sql/DriverManager/setLoginTimeout%28int%20seconds%29.html

person Harold Sota    schedule 31.01.2011
comment
Но я думаю, что реализация setLoginTimeout() недоступна для драйвера jdbc-mysql. - person ihavprobs; 31.01.2011
comment
Хорошо, вот эти: freak-search.com/en/thread/796051/ - person Harold Sota; 31.01.2011
comment
@Haroldis: эта ссылка сгнила. Пожалуйста, включите ваши выводы в ответ. - person Martin Schröder; 21.01.2013