我正在开发一个应用程序,我需要连接N个数据库系统[N范围在1到350之间]。
这个想法是 - 将向用户显示数据库列表,并要求用户从列表中选择任何或所有数据库。
选择数据库后,我需要连接到每个数据库并执行存储过程。
我打算使用普通的旧JDBC并且每次都为它们获取连接[或者通过在多个线程中运行它们]并执行存储过程并关闭连接。
所有这一切都应该在交易中发生。这样做的最佳方式是什么?
如果不是JDBC ......还有其他任何有效的方法吗?
更新 -
存储过程实际上涉及运行某些sql - 例如更新列,为用户授予权限等。
答案 0 :(得分:3)
我创建了一个具有合理最大线程数量的线程池,可以在Executors#newFixedThreadPool()
的帮助下,在10到20个线程之间,并调用单独的DB连接和SP执行任务,每个任务为Callable
使用ExecutorService#invokeAll()
。你想玩线程数和配置文件,毕竟产生最佳性能。
每个Callable
实现都应该将连接详细信息和SP名称作为构造函数参数,以便您可以为不同的数据库调用重用相同的实现。
更新:好的,这是一个网络应用程序。你不想浪费线程。如果它应该由单个并发用户使用,那么您应该确保线程池在请求结束时或在会话的最高端正确shutdown。但是如果它应该由多个并发用户使用,那么您希望在应用程序范围内共享线程池。此外,您还需要确保在webapp关闭时正确关闭它。 ServletContextListener
在这里很有用。
答案 1 :(得分: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;
}
答案 2 :(得分:1)
正如duffymo在他的评论中所指出的,如果你有一个事务协调员和两个阶段提交,你将只能跨多个数据库进行交易。
为此,您需要一个可以处理JTA的J2EE堆栈。如果您在Tomcat或其他没有JTA的容器中运行,则可以下载并安装多个选项。
当然,您需要让Container而不是数据库/存储过程处理事务提交和回滚。
答案 3 :(得分:0)
这听起来像是一团糟,但这是你的问题。
每个数据库需要一个连接池。我不建议您尝试自己处理连接生命周期。让app服务器为您完成。
如果您希望一组数据库参与一个大型事务,则必须使用JDBC XA驱动程序来所有。您还需要一个JTA事务管理器来监督您的交易。
存储过程不能包含任何处理事务的逻辑;你必须让JTA这样做。
您没有说明存储过程正在做什么。如果它不需要返回任何内容,则替代设计可能是JMS,队列和侦听器池。如果我是你,我会担心线程问题。如果可能的话,我会找到一种方法让容器做那些复杂的事情。
答案 4 :(得分:0)
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;
}
}