0

我正在编写一个分析 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).

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

谢谢

4

2 回答 2

1

我认为问题在于您将许多中间层、事务性和持久性逻辑混杂在一个类中。

如果您直接与 ResultSet 打交道,那么您就不会以一种非常面向对象的方式来考虑事物。

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

如果没有,我建议尽可能缩短连接打开的时间。打开一个Connection,获取ResultSet,将其映射到一个对象或数据结构中,在本地范围内关闭ResultSet和Connection,返回映射的对象/数据结构进行处理。

您可以通过这种方式将持久性和处理逻辑分开。通过保持短暂的联系,您可以避免很多悲伤。

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

于 2010-06-01T23:23:32.467 回答
0

经过一段时间的脑筋急转弯,我发现了自己的错误......我想把这个新知识,所以......我去

通过在我的代码中将 Connection 对象声明为静态对象,我犯了一个很大的错误......所以很明显,尽管我为我创建的每个新数据对象创建了一个新的 Connection,但每个事务都通过一个单独的静态连接。

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

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

仅通过使用专用连接进行输入读取和专用连接进行输出写入,我的程序的性能就提高了……但我需要更多!

我对第 3 步和第 4 步的原始方法是在获得结果后立即将每个结果保存到输出中……但我找到了更好的方法:

  • 读取输入数据
  • 处理数字,并将结果放入一堆队列中(每个输出表一个)
  • 一个单独的线程每秒检查任何队列中是否有数据。如果队列中有数据,则将其写入表中。

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


我知道有更好的方法来解决这个特定的问题,但是这个工作得很好。

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

于 2011-03-28T17:33:37.670 回答