質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

4回答

232閲覧

最新の集計結果を適用したいSQL JAVA JDBC

poge

総合スコア15

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

1クリップ

投稿2017/07/14 07:43

編集2017/07/14 08:13

###前提・実現したいこと

  • java7
  • jdbc
  • postgresql

初歩的な質問で恐縮です。

以下の様なテーブルAとテーブルBがあり、
テーブルAにデータを追加していき、テーブルBの件数を更新しようとしています。

テーブルA

idグループ名
1aaa
2bbb
3aaa
4aaa

テーブルB

グループ名件数
aaa3
bbb1

以下の様に処理を記載しました。
1.トランザクションを開く(Connection.setAutoCommit(false))
2.テーブルAへの行追加SQLを実行(insert テーブルA)
3.テーブルBに件数を反映する集計SQLを実行(update テーブルB set ... from(select ... from テーブルA))
4.コミット(Connection.commit())

処理が1つだけ(直列)の場合は上記でうまくいくのですが、並列で実行した場合、
行追加は全て行われるのですが、集計SQLの結果がテーブルAの状態と合致しなくなります。

■例:10並列で処理を実行
テーブルAのレコード数⇒10件
テーブルBの件数フィールド値⇒7
※この場合、本来は10に更新したい

###試したこと
Connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE)
を指定してみましたが、同時更新のため直列化アクセスができませんでした(当然ですが...)

###困っていること
最新の結果が反映されるようにしたいのですが、どういったアプローチをすればいいのかわかりません。
補足条件:テーブル構成は変更できません

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

トランザクションの開始から終了までを1つのメソッドでくくり、

java

1public synchronized void transactionHoge() { 2 //シンクロナイズを書くことで、このメソッドは他からは呼ばれない。 3}

のような制御はいかがですか。トランザクション張ってる間の変動は止まるはずです。

投稿2017/07/14 08:37

akio221

総合スコア716

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

poge

2017/07/14 09:15

回答ありがとうございます。 なるほど、ロジックそのものを同期化してしまえば、並列処理はできずとも目的は達せられそうですね。
guest

0

ベストアンサー

  • 設計について

⇒そもそもテーブルBは必要ですか?
集計時にテーブルAを見るようにしてはいかがでしょうか。
(すみません、他の回答で縛りがあるんですね)

  • SQLの並列処理について

⇒10ではなく7で更新されてしまう原因は理解されているようにも見えますが、
テーブルAに入れた後、コミットしていないため、
同時実行すると以下の順番で更新されると、10以外のデータで更新されます。

(例)
処理1 テーブルA インサート
処理2 テーブルA インサート
処理3 テーブルA インサート
処理1 テーブルB 更新(1件)
処理2 テーブルB 更新(1件)
処理1 コミット
処理3 テーブルB 更新(2件)
処理2 コミット(テーブルB 1件)
処理3 コミット(テーブルB 2件)

テーブルBを残したまま、対策する場合、以下のような方法があります。

<方法1:強制的に直接処理にする>
テーブルBをロック(ロックできなければ、待機)、
テーブルAをインサート、
テーブルBの更新・コミット
テーブルBの解放

<方法2:本当の同時以外は回避する>
テーブルAをインサート、コミット
テーブルBの更新・コミット
※9になる可能性もあります。

  • バグもなく、直接処理ではなく、並列処理させたい!という場合

⇒テーブルAにインサートした直後のテーブルBとの差異は無視するという手もあります。
つまり、参照の時に、
テーブルBの更新、コミットを行ってから、
テーブルBのデータを抽出する。
という方法もあります。
(この場合、そもそも、抽出時に集計した方が早いのですが・・・・・・)

  • その他

⇒テーブル構造のしばりがあっても、
そもそもその項目を使わない(構造はそのまま放置)のもありかとも思います。

投稿2017/07/14 08:36

tomari_perform

総合スコア760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

poge

2017/07/14 08:41 編集

回答いただきありがとうございます。 回答いただいた内容を熟読し、再度考慮してみます。 テーブルBに集計結果を反映しなければならないのは、テーブルA・テーブルBが自身の開発物とは別の連携先システム内のDB内にあるためで、テーブルBは常に最新の状態が保たれていないとならないという制約があるためです...
poge

2017/07/14 09:10

一先ず、開始時にLOCK TABLE テーブルB IN EXCLUSIVE MODEでテーブルBをロックするようにして、目的の動作を達成しました。ありがとうございました。
guest

0

並列で処理したら、他のトランザクションでinsertされた行はcommitされるまで見えないので、
当然誤差がでますよ。

3.テーブルBに件数を反映する集計SQLを実行

を全てのinsertの並列処理のcommitが終わった後に1回やればいいだけだと思いますが、、、

投稿2017/07/14 08:28

szk.

総合スコア1400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

poge

2017/07/14 08:32

回答ありがとうございます。 実際の処理では、insert処理(および更新処理)がWebリクエストに応じて発生するため、全てが終わるという区切りがありません。定周期で集計SQLを実行するのもNGといわれておりまして、どうすればいいか悩んでおります。
szk.

2017/07/14 09:10

1.トランザクション 2.テーブルAへの行追加SQLを実行 4.コミット 上記の処理が終わったら、別スレッドで以下を実行。 1.トランザクション 3.テーブルBに件数を反映する集計SQLを実行 4.コミット これで明確な前後関係ができますが、、、 そもそもどこまでの対応が出来るかですが。。  javaの実装?クラスの作成?ライブラリの追加?SQLの修正?トリガーの追加?その他??
poge

2017/07/14 09:13

なるほど、上記の方法であれば、全てのInsertがコミットされた後に、必ず一度は集計SQLが走りますね。 ありがとうございます。 テーブルAにトリガーを使用する方針で進めていたのですが、DB構成には直接手は加えてほしくないといわれてNGとなってしまいました。
guest

0

テーブルA、Bそれぞれに更新時刻カラムを追加し、最新のものをBにも追加して、
Bテーブル更新時にAの最新時刻がBのものより現在に近ければBを更新。
みたいなアプローチはどうですか?
あいまいな回答で申し訳ないですがアプローチという意味で・・・

投稿2017/07/14 08:06

elz4m

総合スコア69

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

poge

2017/07/14 08:12

回答ありがとうございます。 すみません。後出しの条件で申し訳ないのですが、テーブル構成は変更できない縛りがあります。。。
elz4m

2017/07/14 08:14

Javaのみで更新時刻を保持してみる方法もできそうですが全くスマートではないですね。。。 お力になれずすみません
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問