Javaスレッドまたはエグゼキューターを手伝ってください:いくつかのmysqlの選択、挿入、更新の実行
-
22-10-2019 - |
質問
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
しばらく脳が壊れた後、私は自分の間違いを見つけました...私はこの新しい知識を置きたいので...ここに行きます
私はとても作りました 大ミス コード内の静的オブジェクトとして接続を宣言することにより...明らかに、作成した新しいデータオブジェクトごとに新しい接続を作成したにもかかわらず、すべてのトランザクションは単一の静的接続を通過しました。
その最初の問題が修正されたので、私はデザインテーブルに戻り、私のプロセスが次のとおりであることに気付きました。
- 入力テーブルからIDを読み取ります
- 他の入力表に保存されているステップ1で読み取られたIDに関連するデータのブロックを取ります
- クランチ番号:関連する入力テーブルを読み、それらに保存されているデータを処理します
- 結果を1つ以上の出力テーブルに保存します
- 入力テーブルに保留中のIDがあるときにプロセスを繰り返します
入力読み取り用に専用の接続と出力ライティング用の専用接続を使用するだけで、私のプログラムのパフォーマンスが増加しました...しかし、私はもっと必要でした!
ステップ3と4の私の元のアプローチは、結果の各1つを出力に保存することでした...しかし、私はより良いアプローチを見つけました:
- 入力データをお読みください
- 数字をクランチし、結果をたくさんのキューに入れます(出力テーブルごとに1つ)
- 分離されたスレッドは、キューのいずれかにデータがあるかどうかを毎秒チェックしています。キューにデータがある場合は、テーブルに書き込みます。
したがって、異なる接続を使用して入力タスクと出力タスクを分割し、コアプロセス出力をキューにリダイレクトし、出力ストレージタスクに専用のスレッドを使用することにより、最終的に私が望むものを達成しました:マルチスレッドDML実行!
この特定の問題にはより良いアプローチがあることは知っていますが、これは非常にうまく機能します。
だから...誰かがこのような問題にとどまっているなら...私はこれが役立つことを願っています。
他のヒント
問題は、多くの中間層、トランザクション、および永続的なロジックを1つのクラスに混乱させたことだと思います。
結果を直接扱っている場合、非常にオブジェクト指向の方法で物事について考えていません。
データベースを取得して計算の一部を実行する方法を理解できれば、賢いです。
そうでない場合は、可能な限り最小限の時間を開いたままにすることをお勧めします。接続を開き、結果セットを取得し、オブジェクトまたはデータ構造にマップし、ローカルスコープの結果と接続を閉じて、処理のためにマッピングされたオブジェクト/データ構造を返します。
この方法で、ロジックを分離し、処理し続けます。接続を短命に保つことで、多くの悲しみを救います。
ストアドプロシージャソリューションが遅い場合、インデックスが不十分なためです。別のソリューションは、悪化していなくても同様にパフォーマンスが低下します。説明計画を実行してみて、クエリのいずれかがテーブルスキャンを使用しているかどうかを確認してください。はいの場合、追加するインデックスがいくつかあります。また、トランザクションが長期にわたって行われている場合、ロールバックログが大きいためである可能性があります。切り替える前に、あなたが持っているソリューションで可能な限りすべてを行っていることを確認するためにできることとすべきことがたくさんあります。あなたは多大な努力に進むことができ、それでも根本的な原因に対処することはできません。