简体   繁体   English

“相同”时间的JDBC Open 2连接

[英]JDBC Open 2 Connections at the “same” time

I'm currently trying to open 2 JDBC Connections at the same time, which results in both threads blocking at the "getConnection" call. 我当前正在尝试同时打开2个JDBC连接,这导致两个线程在“ getConnection”调用时阻塞。 I use a self-written TaskManager (which is a simple Thread-Pool for javafx-Tasks with callbacks) to submit my TestConnectionTask with a max Threadcount of 8. When I set the max Threadcount to 1 everything works just fine. 我使用自写的TaskManager(这是带有回调的javafx-Tasks的简单线程池)提交最大线程数为8的TestConnectionTask。当我将最大线程数设置为1时,一切正常。

Here's the relevant code: 以下是相关代码:

Submitting the Tasks: 提交任务:

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);

The TestConnectionTask Class: 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);
    }
}

The DBConnector Class: 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;
    }
}

The Implementations MSSQL and MySQL simply construct it like that: MSSQL和MySQL的实现只是像这样构造它:

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

And last but not least the TaskThreadPool, which is the Superclass of my Project-Spefific TaskManager 最后但并非最不重要的一点是TaskThreadPool,它是我的项目专用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);
    }
}

I'm now using the following synchronized static Method in my DBConnector to open the connections one after the other as a workaround 我现在在DBConnector中使用以下同步静态方法来一个接一个地打开连接,这是一种解决方法

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

Still looking forward to find a solution which allows me to open multiple connections parallel 仍然期待找到一种解决方案,允许我并行打开多个连接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM