JDBC - 连接多个数据库

11

我正在开发一个应用程序,需要连接N个数据库系统[N的范围在1到350之间]。

我们的想法是用户将会得到一个数据库列表并被要求从列表中选择任意一个或全部。

选定数据库后,我需要连接到每个数据库并执行存储过程。

我打算使用普通的JDBC并一次获取一个连接(或通过多线程运行它们),执行存储过程,然后关闭连接。

而且,所有这些操作应该在事务中进行。如何最好地实现呢?

如果不使用JDBC...还有其他高效的方法吗?

更新 -

存储过程实际上涉及运行某些SQL语句 - 例如更新列、授予用户权限等。


1
什么类型的应用程序?桌面还是网络? - skaffman
这是一个网络应用程序。 - jagamot
我的理解是,您并不需要在单个事务中完成这项操作,这是真的吗?否则,还需要考虑更多内容。 - BalusC
我计划在单个事务中完成这个操作...不确定会有多复杂! - jagamot
5个回答

3
我会使用Executors#newFixedThreadPool()创建一个线程池,最大线程数应该在10到20之间。将连接数据库和执行SP的任务分别作为Callable实现,并使用ExecutorService#invokeAll()调用。你可以通过调整线程数并测试性能来找到最佳的线程数量。
每个Callable实现都应该将连接细节和SP名称作为构造函数参数,这样你就可以重复使用相同的实现来进行不同的DB调用。
更新:好的,这是一个Web应用程序。你不想浪费线程。如果它只被单个并发用户使用,那么你应该确保在线程池在请求结束或会话结束时正确地关闭。但如果它被多个并发用户使用,那么你需要在应用程序范围内共享线程池。同样,在Web应用程序关闭时,你需要确保正确地关闭线程池。在这里,ServletContextListener非常有用。

2
如果您可以使用两个连接,建议使用连接池c3p0进行管理。连接两个数据库的声明如下:
public Connection connection1;
public Connection connection2;
DataSource dataSource1;
DataSource dataSource2;

然后是两种类似的方法:
public Connection dbConnect1() throws SQLException {
    ComboPooledDataSource cpds = new ComboPooledDataSource();
    try {
        cpds.setDriverClass("com.mysql.jdbc.Driver");
    } catch (PropertyVetoException e) {
    }
    cpds.setJdbcUrl("jdbc:mysql://localhost:3306/myDatabase1?autoReconnect=true"); 
    cpds.setUser("myMYSQLServerLogin");
    cpds.setPassword("myMYSQLServerPassword");
    cpds.setMinPoolSize(5);
    cpds.setAcquireIncrement(5);
    cpds.setMaxPoolSize(20);
    cpds.setMaxIdleTime(60);
    cpds.setMaxStatements(100);
    cpds.setPreferredTestQuery("SELECT 1");
    cpds.setIdleConnectionTestPeriod(60);
    dataSource1 = cpds;
    connection1 = dataSource1.getConnection();
    return connection1;
}

public Connection dbConnect2() throws SQLException {
    ComboPooledDataSource cpds = new ComboPooledDataSource();
    try {
        cpds.setDriverClass("com.mysql.jdbc.Driver");
    } catch (PropertyVetoException e) {
    }
    cpds.setJdbcUrl("jdbc:mysql://localhost:3306/myDatabase2?autoReconnect=true"); 
    cpds.setUser("myMYSQLServerLogin");
    cpds.setPassword("myMYSQLServerPassword");
    cpds.setMinPoolSize(5);
    cpds.setAcquireIncrement(5);
    cpds.setMaxPoolSize(20);
    cpds.setMaxIdleTime(60);
    cpds.setMaxStatements(100);
    cpds.setPreferredTestQuery("SELECT 1");
    cpds.setIdleConnectionTestPeriod(60);
    dataSource2 = cpds;
    connection2 = dataSource2.getConnection();
    return connection2;
}

只需在循环中处理您的 350 个数据库即可。如果需要清理代码,请从主数据库中提取每个数据库的参数。 - Zon

1
如duffymo在他的评论中指出的那样,如果您有一个事务协调器和两阶段提交,您才能跨多个数据库进行事务处理。
为此,您需要一个将处理JTA的J2EE堆栈。如果您正在Tomcat或另一个没有JTA的容器中运行,则可以下载和安装几个选项。
当然,您需要让容器而不是数据库/存储过程来处理事务提交和回滚。

0

这听起来有点混乱,但这是你的问题。

每个数据库都需要一个连接池。我不建议你尝试自己处理连接生命周期。让应用服务器为你处理它。

如果你想让一组数据库参与一个大事务,你必须使用 JDBC XA 驱动程序,并为所有数据库使用。你还需要一个 JTA 事务管理器来监督你的事务。

存储过程不能包含任何处理事务的逻辑; 你必须让 JTA 去做。

你没有说明存储过程在做什么。如果它不需要返回任何东西,另一种设计可能是使用 JMS、队列和监听器池。如果我是你,我会担心线程问题。如果可以的话,我会找到一种方法让容器替我完成这些复杂的工作。


我猜所有数据库连接URL都保存在一个中央数据库中。我相信我们不想在应用服务器中创建数据源[如我大约有1-350个数据源].....在这种情况下,我猜我需要自己处理连接生命周期,对吗? - jagamot

-1
public static Connection getconnection(String db,String host){
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://"+**Pass Your Host Here 
Like Localhost**+"/"+Pass Your DB Name** +"?useUnicode=yes&characterEncoding=UTF- 
8","root","root");
return con;
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} 
}

在回答中编写代码很好,但同时解释为什么这段代码有效会更好 来自审核 - Vaibhav Vishal

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