帮助java线程和执行程序:同时执行多个MySQL选择,插入和更新

时间:2010-06-01 23:01:17

标签: java mysql multithreading executors

我正在编写一个分析MySQL数据库的应用程序,我需要同时执行几个DML;例如:

// In ResultSet rsA: Select * from A;
rsA.beforeFirst();
while (rsA.next()) {
   id = rsA.getInt("id");
   // Retrieve data from table B: Select * from B where B.Id=" + id;
   // Crunch some numbers using the data from B
   // Close resultset B
}

我正在声明一组数据对象,每个数据对象都有自己的数据库连接,而数据库又调用了几种数据分析方法。问题是所有线程都使用相同的连接,因此所有任务都抛出异常:“超出锁定等待超时;尝试重新启动事务”

我相信有一种方法可以编写代码,使得任何给定对象都有自己的连接,并独立于任何其他对象执行所需的任务。例如:

DataObject dataObject[0] = new DataObject(id[0]);
DataObject dataObject[1] = new DataObject(id[1]);
DataObject dataObject[2] = new DataObject(id[2]);
...
DataObject dataObject[N] = new DataObject(id[N]);
// The 'DataObject' class has its own connection to the database, 
// so each instance of the object should use its own connection. 
// It also has a "run" method, which contains all the tasks required.
Executor ex = Executors.newFixedThreadPool(10);

for(i=0;i<=N;i++) {
   ex.execute(dataObject[i]);
}
// Here where the problem is: Each instance creates a new connection,
// but every DML from any of the objects is cluttered in just one connection
// (in MySQL command line, "SHOW PROCESSLIST;" throws every connection, and all but
// one are idle).

你能指出我正确的方向吗?

由于

2 个答案:

答案 0 :(得分:1)

我认为问题在于你将很多中间层,事务性和持久性逻辑混淆在一个类中。

如果您直接处理ResultSet,那么您不会以面向对象的方式思考问题。

如果你能弄清楚如何让数据库进行一些计算,你就很聪明。

如果没有,我建议尽可能少地保持连接打开。打开Connection,获取ResultSet,将其映射到对象或数据结构,关闭ResultSet和Connection in local scope,然后返回映射的对象/数据结构进行处理。

通过这种方式保持持久性和处理逻辑。通过保持短暂的联系,你可以为自己省去很多悲伤。

如果存储过程解决方案很慢,可能是由于索引不佳。如果不是更糟,另一种解决方案的表现同样糟糕。尝试运行EXPLAIN PLAN并查看您的任何查询是否正在使用TABLE SCAN。如果是,您需要添加一些索引。如果您的事务长时间运行,也可能是由于大型回滚日志。您可以而且应该做的事情很多,以确保您在切换之前已经完成了所有可能的解决方案。你可以付出很大的努力,但仍然没有解决根本原因。

答案 1 :(得分:0)

经过一段时间的大脑突破后,我想出了自己的错误......我想把这些新知识,所以...我来这里

我通过在我的代码中将Connection objet声明为静态对象来犯了一个非常大错误 ...很明显,尽管我为每个创建的新数据对象创建了一个新的Connection,但是每个事务经历了一次静态的连接。

在第一个问题得到纠正后,我回到了设计表,并意识到我的过程是:

  1. 从输入表中读取ID
  2. 获取与步骤1中读取的Id相关的数据块,存储在其他输入表中
  3. 紧缩号码:阅读相关的输入表并处理存储在其中的数据
  4. 将结果保存在一个或多个输出表中
  5. 在输入表
  6. 中有待处理的ID时重复此过程

    只需使用专用连接进行输入读取和输出写入专用连接,我的程序性能就会提高......但我还需要更多!

    我对步骤3和步骤4的原始方法是,只要我拥有它们,就将每个结果保存到输出中......但我找到了更好的方法:

    • 阅读输入数据
    • 压缩数字,并将结果放在一堆队列中(每个输出表一个)
    • 如果任何队列中有数据,则分离的线程每秒都会检查一次。如果队列中有数据,请将其写入表中。

    因此,通过使用不同的连接划分输入和输出任务,并通过将核心进程输出重定向到队列,并通过使用专用线程进行输出存储任务,我终于实现了我想要的:多线程DML执行!


    我知道有更好的方法可以解决这个问题,但是这个方法非常好。

    所以...如果有人遇到这样的问题......我希望这有帮助。