【问题标题】:Is MariaDB JDBC driver ignoring connection timeout?MariaDB JDBC 驱动程序是否忽略了连接超时?
【发布时间】:2018-11-27 10:26:24
【问题描述】:

在我们正在开发的应用程序中,用户可以通过在文本字段中输入任意 JDBC 连接 URL 来连接到外部 RDBMS。我们的一位客户报告说,当他不小心尝试使用 MySQL JDBC URL 连接到 Microsoft SQL Server 时,我们的应用程序服务器(无限期地)冻结在 0% CPU。

下面的 Java sn -p 说明了这种情况:

public static void main(String[] args){

    // note: the application running on localhost:1433 is ACTUALLY
    // an MS SQL Server instance!
    String jdbcUrl = "jdbc:mysql://localhost:1433/my-db";

    // enable JDBC Driver Manager logging
    DriverManager.setLogWriter(new PrintWriter(System.err));

    // set a timeout of 5 seconds for connecting (which is blissfully ignored!)
    DriverManager.setLoginTimeout(5);

    // open the connection (which should fail, but freezes instead)
    try (Connection c =  DriverManager.getConnection(jdbcUrl)){
        System.out.println("This should never be reached due to wrong JDBC URL.");
    }catch(Exception e){
        System.out.println("This is expected (but never printed).");
    }
    System.out.println("This is never printed either.");
}

运行 sn-p:

  • 在 localhost:1433 上运行 SQL Server 实例(内容无关紧要)
  • 拥有 MariaDB JDBC 驱动程序版本 2.2.5。 (最新)在您的类路径中。

问题:

  • 1) 这可能是 MariaDB JDBC 驱动程序中的错误吗?谷歌搜索没有发现这方面的任何信息。
  • 2) 我应该如何解决这个问题?我不希望我的服务器在用户意外插入无效的 JDBC URL 时冻结。

我尝试了其他几个 JDBC 驱动程序(MySQL、DB2、Oracle...),它们都很好地处理了这个问题,只有 MariaDB JDBC 驱动程序冻结了 JVM。

【问题讨论】:

    标签: java mariadb


    【解决方案1】:

    这是我为解决问题所做的。诀窍是在连接中添加socketTimeout。要修复问题中的程序,只需将 JDBC URL 修改为:

    jdbc:mysql://localhost:1433/my-db?socketTimeout=2000

    This answer 到一个相关问题是我需要的提示。

    【讨论】:

    • 另外,如果你不控制JDBC URL(如我的场景),你可以使用Driver#connect(String, Properties)中的Properties映射来传递socketTimeout
    • 如果你使用一个小的socketTimeout,它可能会导致问题。它将在长时间运行的 sql 查询期间终止您的连接。
    【解决方案2】:

    答案 1:是的,这是一个错误。他们在执行 mariadb jdbc 驱动时错过了使用登录超时。

    答案 2:我通过使用包含 getConnection 方法的任务来解决问题。如果此任务尚未完成,则在定义的登录时间后停止。这是我的实现。

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.util.Properties;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.FutureTask;
    import java.util.concurrent.TimeUnit;
    
    import org.mariadb.jdbc.util.DefaultOptions;
    
    public class ConnectionTest {
    
        private static final String CONNECTION_STRING = "jdbc:mariadb://localhost:3306/test";
        private static final String USER = "root";
        private static final String PW = "";
        private static final int LOGIN_TIMEOUT_SEC = 2;
    
        public static void main(String[] args) throws Exception {
            var test = new ConnectionTest();
            Connection connection = test.getConnection();
            if(connection != null && connection.isValid(LOGIN_TIMEOUT_SEC)) {
                System.out.println("Connected!");
            }
        }
    
        private Connection getConnection() throws Exception {
            ConnEstablishSync sync = new ConnEstablishSync();
    
            Properties conProps = new Properties();
            conProps.setProperty(DefaultOptions.USER.getOptionName(), USER);
            conProps.setProperty(DefaultOptions.PASSWORD.getOptionName(), PW);
    
            FutureTask<Connection> task = new FutureTask<>(() -> {
                Connection c = DriverManager.getConnection(CONNECTION_STRING, conProps);
                if(sync.canceled && c != null) {
                    c.close();
                    c = null;
                }
                return c;
            });
    
            Connection connection = null;
    
            ExecutorService executor = Executors.newSingleThreadExecutor();
            try {
                executor.submit(task);
                connection = task.get(LOGIN_TIMEOUT_SEC, TimeUnit.SECONDS);
            } finally {
                sync.canceled = true;
                task.cancel(true);
                executor.shutdown();
            }
            return connection;
        }
    
        private static class ConnEstablishSync {
            private volatile boolean canceled = false;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-11
      • 1970-01-01
      • 2014-02-16
      • 1970-01-01
      • 2012-11-15
      • 1970-01-01
      • 2020-11-23
      • 2021-06-22
      相关资源
      最近更新 更多