java 如何强制 DriverManager.getConnection() 方法调用超时?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4850957/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to force timeout for DriverManager.getConnection() method call?
提问by ihavprobs
I have an application which will establish DB connection with MySQL and execute queries. Sometimes the DriverManager.getConnection()
method call takes 2 seconds and sometimes it takes 30 seconds. Is there any way to control this method to timeout after 2 seconds?
我有一个应用程序,它将与 MySQL 建立数据库连接并执行查询。有时DriverManager.getConnection()
方法调用需要 2 秒,有时需要 30 秒。有没有办法控制这个方法在2秒后超时?
DriverManager.setLoginTimeout()
doesn't seem to work.
DriverManager.setLoginTimeout()
似乎不起作用。
Actually, am able to set timeout for statement.executeQuery()
by sleeping the thread for my timeout value and closing the connection after wakeup. But its the connection establishment part where I couldn't really set the timeout.
实际上,我可以statement.executeQuery()
通过为我的超时值休眠线程并在唤醒后关闭连接来设置超时。但它的连接建立部分我无法真正设置超时。
Would appreciate any help.
将不胜感激任何帮助。
采纳答案by Rune Aamodt
If there's no other options, you could always just execute the call in a separate thread, which you abort/ignore if it doesn't finish in 2 secs.
如果没有其他选项,您总是可以在单独的线程中执行调用,如果它没有在 2 秒内完成,您可以中止/忽略该调用。
EDITHere's an example of what I was thinking:
编辑这是我在想的一个例子:
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 ;
}
}
Then you can just call the static Dummy.getConnection() method other places in your code. One drawback is that this method will always take 2 secs, but changing it to return immediately when the thread is finished isn't too hard.
然后您可以在代码中的其他地方调用静态 Dummy.getConnection() 方法。一个缺点是此方法将始终需要 2 秒,但将其更改为在线程完成后立即返回并不太难。
回答by bestro
You can use ExecutorService
interface from Java. Below is a sample of what you need to do.
您可以使用ExecutorService
Java 的接口。以下是您需要执行的操作的示例。
Future<Boolean> future = executor.submit(YOUR_METHOD);
future.get(TIMEOUT_YOU_NEED, TimeUnit.SECONDS);
回答by anpadia
Thank you to codebolt, I don't know if it's the best solution but this works for me. A 10 seconds time out.
感谢 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 ;
}
}
And the call:
和电话:
Dummy a = new Dummy();
connection = a.getConnection();
if (connection != null) {....
回答by SteveGreenslade
Try setting the socketTimeout (Time in milliseconds) on the connection URL or on the connection pool (if you are using pooling). Take care not to set this value too low or it will overwrite the statement timeout value.
尝试在连接 URL 或连接池(如果您使用池)上设置 socketTimeout(时间以毫秒为单位)。注意不要将此值设置得太低,否则会覆盖语句超时值。
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>
Setting this fixed the timeout issue for me.
设置它为我解决了超时问题。
回答by stackoverflowuser2010
I expanded upon the answers by CodeBolt and anpadia to make the following complete class. It has only one static method that accepts all needed connection parameters, including the timeout duration. Additionally, the method wil also throw SQLException and ClassNotFoundException if they occur.
我扩展了 CodeBolt 和 anpadia 的答案,制作了以下完整课程。它只有一个接受所有需要的连接参数的静态方法,包括超时持续时间。此外,该方法还会在发生 SQLException 和 ClassNotFoundException 时抛出它们。
Usage:
用法:
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);
Below is the implementation:
下面是实现:
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);
}
}
}