驱动程序管理器获取连接的连接超时

29
我试图使用标准的JDBC方法连接到数据库。
connection = DriverManager.getConnection(url, username, password);

连接的超时时间是否有最大值,连接存在多长时间,可以增加值吗?我想在某些情况下保持连接永久开放,这是一个好主意吗?

6个回答

38

您可以这样在DriverManager上设置超时时间:

 DriverManager.setLoginTimeout(10);
 Connection c = DriverManager.getConnection(url, username, password);

这意味着如果在给定时间内连接无法打开,那么它将超时。

如果您不关闭连接,则可以永久保持连接,但这可能不是一个好主意。应该尽快关闭不再使用的连接。

如果您想优化打开和关闭连接的操作,则可以使用连接池。


5
如果我没记错的话,这只是设置DriverManager在等待返回连接时的超时时间。它并没有设置连接本身的超时时间。另请参见:http://java.sun.com/javase/6/docs/api/java/sql/DriverManager.html#setLoginTimeout%28int%29 - BalusC
1
没错 @BalusC。就像我之前提到的那样,timeout 只决定 DriverManager 等待连接的时间,而不影响连接保持打开状态的时间。 - Vincent Ramdhanie
2
我必须承认(你可能也是),这是主题标题中直接表述的问题的正确答案。但是,主题消息中实际的问题却是不同的。 - BalusC
2
DriverManger.setLoginTimeout(10) 对于 MySQL 驱动程序对我无效。我认为唯一的方法是使用线程来实现。 - styfle
2
你的线程真是好笑 - 你可以通过创建一个属性对象 prop,然后 prop.put("connectTimeout", "2000")(其中的“2000”是以毫秒为单位的超时时间),最后将你的 prop 对象与你的 URL 一起传递给 DriverManager.getConnection() 方法来轻松实现。 - flamming_python
显示剩余2条评论

34

这个值通常由数据库控制,您无法使用代码控制。它取决于所使用的DB服务器,通常在30分钟到1小时左右。

另一方面,保持Connection永久打开是一个非常糟糕的想法。最佳做法是在尽可能短的范围内获取和关闭ConnectionStatementResultSet,以避免资源泄露和泄漏和超时引起的潜在应用程序崩溃。

确实,连接到数据库是一个昂贵的任务。如果您的应用程序需要运行相对较长时间并经常连接到数据库,则考虑使用连接池来提高连接性能。如果您的应用程序是Web应用程序,则请查看应用程序服务器的文档,它通常提供连接池设施,比如DataSource。如果是客户端应用程序,请寻找已证明其稳定性多年的第三方连接池库,比如Apache Commons DBCP(通常用于许多应用程序服务器)、C3P0(Hibernate中使用)和Proxool(如果您需要XA连接)。

请注意,使用连接池时,仍然必须编写正确的JDBC代码,即在尽可能短的范围内获取并且关闭所有资源。连接池将负责实际关闭连接或将其释放回池以供进一步重用。

您可以从这篇文章中了解如何以正确的方式执行JDBC基础知识。

希望这有所帮助,祝您编码愉快。


3
DBCP是一个极其糟糕的连接池,绝对不要使用它。 - erickson
有趣。当它用作Tomcat 6.0托管数据源的味道时,我从未遇到过严重的问题。能详细说明一下吗? - BalusC
7
当资源的创建需要一定时间时,你希望使用池来管理资源。DBCP(或者实际上是底层的资源池)在生产新对象时会锁定整个池子,以防止已经完成工作并试图返回资源的线程被阻塞。同时,其他线程也将被阻塞,因为它们正试图获取这些资源。由于这些锁定请求没有使用并发包,所以它们无法被中断。这会影响正常情况下的性能。如果数据库出现问题,情况会变得非常糟糕、非常快。 - erickson
4
是的,说得好。对于Tomcat最好使用org.apache.tomcat.jdbc.pool.DataSourceFactory进行替换。感谢提醒,+1。 - BalusC
通用连接池(UCP)是一个很好的Java连接池。请查看UCP开发人员指南(https://docs.oracle.com/database/121/JJUCP/toc.htm)以获取更多详细信息。在类路径中只需要ucp.jar即可。 - Nirmala

10

以下是使用Connector/J MYSQL驱动程序的方法:

String qqq = "jdbc:mysql://localhost/Test?connectTimeout=TIME_IN_MILLIS";
conn = DriverManager.getConnection(qqq, db_user, db_pass);

setLoginTimeout() 没有任何作用, 在我尝试之后,这种方式对我有效.


5
连接超时应该使用 connectTimeout=TIME_IN_SECONDS,而不是 connectTimeout=TIME_IN_MILLIS。更多信息请参考此处:http://dev.mysql.com/doc/refman/5.1/en/mysql-command-options.html#option_mysql_connect_timeout - hcarrasko
不,connectTimeout=TIME_IN_MILLIS 是指参考这个文档 - You're awesome

7

我只是转发用户flamming_python的评论作为答案,因为它对我有用:

dbConnectionString = "jdbc:mysql://"+dbHost+":"+dbPort+"/"+dbTable+"?user="+dbUser+"&password="+dbPassword;
Properties properties = new Properties();
properties.put("connectTimeout", "2000");
dbConnect = DriverManager.getConnection(dbConnectionString, properties);

原始评论:
"你的帖子让我笑了 - 你可以通过创建一个属性对象prop,然后prop.put("connectTimeout", "2000")(其中“2000”是以毫秒为单位的超时时间),然后将您的prop对象与您的url一起传递给DriverManager.getConnection()方法,就可以轻松实现"


这对我来说是有效的,现在没有超时错误了。从API的javadoc中可以看到,“通常至少应包括一个“用户”和“密码”属性”。我测试了h2数据库。 - Leon

2
如bestro所建议的,可以使用与超时相关联的future。例如:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Connection> future = executor.submit(new Callable<Connection>() {

    @Override
    public Connection call() throws Exception {
        Connection con = DriverManager.getConnection(url, username, password);
        return con;
    }
});

Connection con = null;
try {
    con = future.get(5, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
    Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
}
executor.shutdownNow();

if (con == null) {
    System.out.println("Could not establish connection");
} else {
    System.out.println("Connection established!");
}

-3
你可以使用Java中的ExecutorService接口。以下是您需要执行的示例。
Future<Boolean> future = executor.submit(YOUR_METHOD);
future.get(TIMEOUT_YOU_NEED, TimeUnit.SECONDS);

1
一个糟糕的想法。它创建了一个ThreadFactory和一个Thread,并在并行运行连接时实现了get()的超时,同时使得实际的连接没有真正中止的方法。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接