[英]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.