Прервать / отменить застрявший вызов connect () - PullRequest
4 голосов
/ 10 ноября 2009

Иногда, когда я вызываю connect () на стороннем проприетарном драйвере JDBC, он никогда не возвращается, и трассировка стека показывает, что он завис в ожидании чтения сокета (обычно). Есть ли общий способ принудительно отменить эту операцию из другого потока? Это блокирующий вызов ввода / вывода, поэтому Thread.interrupt () не будет работать, и я не могу напрямую закрыть сокет, потому что у меня нет доступа к нему, поскольку он создан внутри проприетарного кода.

Я ищу универсальные решения, потому что у меня гетерогенная среда БД (Oracle, MySQL, Sybase и т. Д.). Но приветствуются также предложения для конкретного водителя. Спасибо,

Ответы [ 4 ]

2 голосов
/ 10 ноября 2009

Ах ... радости использования библиотек с закрытым исходным кодом ...

Если interrupt() не работает, и вы не можете установить какое-то время ожидания, то я думаю, что нет безопасного способа сделать это. Вызов Thread.kill() может сделать работу, но метод устарел, потому что он ужасно небезопасен. И это тот сценарий, когда небезопасность Thread.kill() может вернуться и укусить вас.

Я предлагаю вам просто закодировать свое приложение, чтобы отказаться от застрявшего потока. Предполагая, что ваше приложение не пытается повторно подключиться к БД, застрявший поток не требует больших затрат.

В качестве альтернативы используйте лучший драйвер JDBC. (И когда вы выходите из дома, пожаловайтесь поставщику на то, что его водитель слишком негибкий. Есть небольшая вероятность, что кто-то вас послушает ...)

2 голосов
/ 10 ноября 2009

Не существует стандартного интерфейса JDBC для установки тайм-аутов подключения или чтения, поэтому вы обязаны использовать проприетарные расширения, если драйвер JDBC вообще поддерживает тайм-ауты. Для тонкого драйвера Oracle JDBC вы можете, например, установите системные свойства "oracle.net.CONNECT_TIMEOUT" и или "oracle.jdbc.ReadTimeout" или передайте экземпляр Properties в DriverManager.getConnection с этими установленными свойствами. Хотя это не совсем хорошо документировано, специфические свойства Oracle перечислены в документации API .

Для других драйверов JDBC документация должна содержать соответствующие ссылки.

1 голос
/ 10 ноября 2009

По крайней мере один драйвер JDBC (не один из тех, что вы перечислили, тем не менее) будет корректно закрывать соединение, если поток, в котором выполняется эта попытка соединения, прерывается. Я не знаю, будет ли это работать для всех водителей.

0 голосов
/ 10 ноября 2009

Это проблема с Java, а не с драйвером JDBC. При определенных обстоятельствах вызов подключения через сокет игнорирует параметры тайм-аута и может занять минуты, чтобы вернуться. Это происходит с нами, когда брандмауэр блокирует порт. Это происходит со всеми TCP-соединениями (HTTP, RMI).

Единственное решение, которое я нахожу, это открыть соединение в другом потоке, как это,

private static final ExecutorService THREADPOOL
       = Executors.newCachedThreadPool();

   private static <T> T call(Callable<T> c, long timeout, TimeUnit timeUnit)
       throws InterruptedException, ExecutionException, TimeoutException
   {
       FutureTask<T> t = new FutureTask<T>(c);
       THREADPOOL.execute(t);
       return t.get(timeout, timeUnit);
   }

   try {
       Data data = call(new Callable<Data>() {
           public Data call() throws Exception
           {
               // Open connection, get data here
               return data;
           }, 2, TimeUnit.SECONDS);
   } catch (TimeoutException e) {
       System.err.println("Data call timed-out");
   }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...