Java 如何强制DriverManager.getConnection()方法调用超时?

Java 如何强制DriverManager.getConnection()方法调用超时?,java,timeout,database-connection,Java,Timeout,Database Connection,我有一个应用程序,它将与MySQL建立DB连接并执行查询。有时调用DriverManager.getConnection()方法需要2秒,有时需要30秒。有没有办法控制此方法在2秒后超时 DriverManager.setLoginTimeout()似乎不起作用 实际上,我可以为语句.executeQuery()设置超时,方法是将线程休眠为我的超时值,并在唤醒后关闭连接。但这是连接建立部分,我无法真正设置超时 非常感谢您的帮助。下面是一个如何使用的示例: 如果没有其他选项,您可以始终在单独的线程

我有一个应用程序,它将与MySQL建立DB连接并执行查询。有时调用
DriverManager.getConnection()
方法需要2秒,有时需要30秒。有没有办法控制此方法在2秒后超时

DriverManager.setLoginTimeout()
似乎不起作用

实际上,我可以为
语句.executeQuery()设置超时,方法是将线程休眠为我的超时值,并在唤醒后关闭连接。但这是连接建立部分,我无法真正设置超时


非常感谢您的帮助。

下面是一个如何使用的示例:


如果没有其他选项,您可以始终在单独的线程中执行调用,如果调用未在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秒,但将其更改为在线程完成后立即返回并不太困难。

尝试在连接URL或连接池(如果使用池)上设置socketTimeout(时间以毫秒为单位)。注意不要将此值设置得太低,否则会覆盖语句超时值

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



设置此选项为我解决了超时问题。

您可以使用Java中的
ExecutorService
接口。下面是您需要做的示例

Future<Boolean> future = executor.submit(YOUR_METHOD);
future.get(TIMEOUT_YOU_NEED, TimeUnit.SECONDS);
Future=executor.submit(您的_方法);
future.get(您需要的超时,TimeUnit.SECONDS);

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

我扩展了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);
        }
    }
}
导入java.sql.DriverManager;
导入java.sql.Connection;
导入java.sql.SQLException;
公共类ConnectWithTimeout扩展线程{
私有静态字符串url;
私有静态字符串_用户;
私有静态字符串\u密码;
专用静态字符串驱动程序;
私有静态易失性连接_Connection=null;
私有静态易失性布尔值_sleep=true;
私有静态易失性SQLException _SQLException=null;
私有静态易失性ClassNotFoundException _ClassNotFoundException=null;
@凌驾
公开募捐{
试一试{
Class.forName(_驱动程序);
_connection=DriverManager.getConnection(\u url、\u用户、\u密码);
}
catch(SQLException-ex){
_sqlException=ex;
}
捕获(ClassNotFoundException ex){
_classNotFoundException=ex;
}
_睡眠=假;
}
公共静态连接getConnection(字符串url,
字符串用户,
字符串密码,
字符串驱动程序,
整数时间(秒)
抛出SQLException,ClassNotFoundException{
checkStringOrThrow(url,“url”);
checkStringOrThrow(用户,“用户”);
checkStringOrThrow(密码,“密码”);
checkStringOrThrow(驾驶员,“驾驶员”);
如果(超时秒数<1){
抛出新的IllegalArgumentException(
“TimeOutingSeconds必须为正”);
}
_url=url;
_用户=用户;
_密码=密码;
_司机=司机;
ConnectWithTimeout conn=新的ConnectWithTimeout();
连接开始();
试一试{
对于(int i=0;i
您使用的驱动程序和数据库是什么?如何中止线程?在2秒后中断线程不起作用。如果您认为必须中止线程,您可以随时对其调用stop(),但这是一种不推荐的方法,因此请先阅读文档中的任何潜在陷阱。您也可以在忽略它并继续运行时让它继续运行。抱歉,但是thread.stop()说“如果目标线程等待很长时间(例如,在条件变量上),应该使用中断方法来中断等待。”但在我的情况下,interrupt()没有帮助。我可以知道原因吗?但是我认为setLoginTimeout()实现对于jdbc mysql驱动程序是不可用的。请在答案中包含您的发现。发布者:
如果将getConnection()方法设置为静态,则不必创建从未使用过的对象。更进一步,您可以将驱动程序类名、URL、用户名和密码参数设置为getConnection(),并具有相当通用的功能。
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);
        }
    }
}