JDBC在“相同”时间打开2个连接

时间:2017-05-11 11:30:38

标签: java mysql sql-server multithreading jdbc

我目前正在尝试同时打开2个JDBC连接,这导致两个线程在“getConnection”调用时阻塞。 我使用自编写的TaskManager(这是一个简单的线程池,用于带回调的javafx-Tasks)来提交我的TestConnectionTask,其最大线程数为8.当我将最大线程数设置为1时,一切正常。

以下是相关代码:

提交任务:

TaskManager.getInstance().submitTask(new TestConnectionTask(
    new MSSQLConnector(),
    this.dbConnectController1.getModel().getHost(),
    this.dbConnectController1.getModel().getUser(),
    this.dbConnectController1.getModel().getPassword(),
    this.dbConnectController1.getModel().getDatabase(),
    5-- timeout in seconds
), this::onDB1Connected);

TaskManager.getInstance().submitTask(new TestConnectionTask(
    new MySQLConnector(),
    this.dbConnectController2.getModel().getHost(),
    this.dbConnectController2.getModel().getUser(),
    this.dbConnectController2.getModel().getPassword(),
    this.dbConnectController2.getModel().getDatabase(),
    5-- timeout in seconds
), this::onDB2Connected);

TestConnectionTask类:

public class TestConnectionTask extends Task<SavingDBConnector>
{
    private final DBConnector connector;
    private final String host;
    private final String user;
    private final String password;
    private final String database;
    private final int timeout;

    public TestConnectionTask(DBConnector connector, String host, String user, String password, String database, int timeout)
    {
        super();
        updateTitle("Verbindungstest");

        this.connector = connector;
        this.host = host;
        this.user = user;
        this.password = password;
        this.database = database;
        this.timeout = timeout;
    }

    @Override
    protected SavingDBConnector call() throws Exception
    {
        updateProgress(0L, 2L);
        updateMessage("Verbindungsversuch");

        try (Connection conn = this.connector.openConnection(this.host, this.user, this.password, this.database, this.timeout))
        {
            updateProgress(1L, 2L);
        }
        catch (Exception e)
        {
            updateMessage("Beim Herstellen der Verbindung ist ein Fehler aufgetreten");
            throw e;
        }

        updateProgress(2L, 2L);
        updateMessage("Verbindung erfolgreich hergstellt");

        return new SavingDBConnector(this.connector, this.host, this.user, this.password, this.database, this.timeout);
    }
}

DBConnector类:

public abstract class DBConnector
{
    private final String jdbcClassName;
    private final String jdbcSubprotocol;
    private boolean jdbcClassLoaded;

    public DBConnector(String jdbcClassName, String jdbcSubprotocol)
    {
        this.jdbcClassName = jdbcClassName;
        this.jdbcSubprotocol = jdbcSubprotocol;
        this.jdbcClassLoaded = false;
    }

    public Connection openConnection(String host, String user, String password, String database, int timeout) throws SQLException, ClassNotFoundException
    {
        if (!this.jdbcClassLoaded)
        {
            Class.forName(this.jdbcClassName);
            this.jdbcClassLoaded = true;
        }

        Properties properties = new Properties();
        properties.setProperty("User", user);
        properties.setProperty("Password", password);

        if (timeout > 0)
        {
            properties.setProperty("LoginTimeout", Integer.toString(timeout));
        }

        Connection conn = DriverManager.getConnection(String.format("jdbc:%s://%s", this.jdbcSubprotocol, host), properties);
        conn.setCatalog(database);

        return conn;
    }
}

实现MSSQL和MySQL只是简单地构建它:

super("com.microsoft.sqlserver.jdbc.SQLServerDriver", "sqlserver");
and
super("com.mysql.jdbc.Driver", "mysql");

最后但并非最不重要的是TaskThreadPool,它是我的Project-Spefific TaskManager的超类

public class TaskThreadPool
{
    private int maxThreadCount;
    private int currentThreadCount;
    private final Object lockCurrentThreadCount;
    private final ConcurrentLinkedQueue<TaskWithCallback<?>> queue;

    public TaskThreadPool()
    {
        this.maxThreadCount = 1;
        this.currentThreadCount = 0;
        this.lockCurrentThreadCount = new Object();
        this.queue = new ConcurrentLinkedQueue<>();
    }

    public void setMaxThreadCount(int maxThreadCount)
    {
        this.maxThreadCount = maxThreadCount;
    }

    public int getMaxThreadCount()
    {
        return this.maxThreadCount;
    }

    public <T> void submitTask(Task<? extends T> task, TaskCallback<T> callback)
    {
        this.queue.offer(new TaskWithCallback<>(task, callback));

        synchronized (this.lockCurrentThreadCount)
        {
            if (this.currentThreadCount < this.maxThreadCount)
            {
                this.currentThreadCount++;

                Thread thread = new Thread(this::threadRun);
                thread.setDaemon(true);
                thread.start();
            }
        }
    }

    private void threadRun()
    {
        while (true)
        {
            TaskWithCallback<?> taskWithCallback;
            while ((taskWithCallback = this.queue.poll()) != null)
            {
                taskWithCallback.run();
            }

            synchronized (this.lockCurrentThreadCount)
            {
                // Sonst möglicherweise tote Tasks
                if (this.queue.isEmpty())
                {
                    this.currentThreadCount--;
                    break;
                }
            }
        }
    }

    private class TaskWithCallback<T> implements Runnable
    {
        private final Task<? extends T> task;
        private final TaskCallback<T> callback;

        public TaskWithCallback(Task<? extends T> task, TaskCallback<T> callback)
        {
            this.task = task;
            this.callback = callback;
        }

        @Override
        public void run()
        {
            this.task.run();
            if (this.callback != null)
            {
                Platform.runLater(() -> this.callback.onTaskCompleted(this.task.getValue()));
            }
        }
    }

    public interface TaskCallback<T>
    {
        public void onTaskCompleted(T result);
    }
}

1 个答案:

答案 0 :(得分:0)

我现在在DBConnector中使用以下同步静态方法一个接一个地打开连接作为解决方法

private synchronized static Connection getConnection(String url, Properties info) throws SQLException
{
    return DriverManager.getConnection(url, info);
}

仍然期待找到一个允许我打开多个并行连接的解决方案