レコードロック解除待ちが解除されない時、アボートさせてそれを把握し、処理制御
データはSQL Serverを使っています。
販売管理システムで
Aさんが商品コード1番と2番で売上入力し、保存。
Bさんは商品コード2番と1番で売上入力し、Aさんと同じタイミングで同時に保存。
入力タスクを終えて、
親バッチ処理制御タスクから、保存バッチタスクを呼んでおります。
メモリワーク上で入力した売上明細情報を、保存バッチタスクでSQL Serverへ保存。
・物理トランザクション
・トランザクション開始=タスク前
・エラー発生時=A アボート にしております。
保存バッチタスクの在庫データ更新でデッドロックが起きかねないと思っています。
そこで思ったのが
RetryOperationTime コマンド処理のリトライ間隔 を
600(10分) 改め 60(1分)といった短い時間へ変更し、
保存バッチタスクは
エラー発生時=A アボートのままで
エラーイベントで、タスク処理変数を更新して
「少し待ってから再度保存してください!」といったメッセージを表示し
入力タスクに戻れるようにする。
こうする事で、デッドロックが起きた2台は、伝票保存は中断されて
ひとまず入力タスクに戻れて、タイミングずらして保存すれば
デッドロック問題から解消される、なんて事を期待して
どうにか実験してみたいと思います。
デッドロックを回避するという1点だけの話で言えば
レコード毎トランザクションに変更するのが容易な事でしょうか?
-
遅延トランザクションを利用するのとできる限り伝票単位ではなく明細単位で更新するのが望ましいと思います。
-
ISHIJIMAさんありがとうございます。
売上明細などの入力の際中は、全てメモリワーク上で編集し
SQL Server上のデータへ書き込みなどしておりません。保存する時のバッチ処理でトランザクションを開始し、
SQL Serverのデータに書込みをしております。
この場合、遅延トランザクションである必要は無いのでしょうね。 -
メモリで編集して行っていること自身が問題があると思います。(レコードロック等の回避の為)
メモリを使用せずに遅延トランザクションで行えばすべて解決すると思います。
今のままのメモリを使用して伝票形式を行おうとするとデッドロック等の回避を行う羽目になります。
-
データリポジトリの数値型項目のカラム特性に、「更新形式」というオプションがあります。
ここのデフォルトは「A=値更新」となっており、下位互換ですが、SQL系列のDBを使う場合は、選択肢に「D=差分更新」というのが使えます。
これを使うと、複数端末からの同時更新が発生しても整合性が維持されます。
詳細はマジック社のRIAトレーニング3日間で解説しているのですが、SQLをご使用中でしたら、ぜひこの機能を試されることをお勧めします。
-
いつもお世話になっております。
アドバイスありがとうございます。既存システムの売上伝票入力PG等が
SQL Serverデータ → メモリW
メモリWで明細入力 → SQL Serverへ書き戻す
という作りになっております。SQL Serverデータのロックが起きるのは、
保存バッチタスク突入時だけなのですが。遅延トランザクションを使う場合、SQL Serverデータへ
直接入力、更新などを行う作りになるのだと思っております。新規案件で遅延トランザクションも検討したいと思います。
遅延トランザクションだとデッドロックは生じないのでしょうか?
-
デットロックはトランザクション等の問題ではなくシステム構造の問題だと思っています。
商品コード1番と2番
商品コード2番と1番
この処理を1つのトランザクション内で行うという事に問題があると思います。
この構造を改善しない限り問題は発生します。
遅延の場合はどちらかが途中で失敗してロールバックされて整合が保たれるという事だと思っています。
その整合を保つ処理を自分で考えて処理を作らなければならないのではないかと
違っていたらすみません。
-
tandaさん、ISHIJIMAさん ありがとうございます。
SQL系DBの数値型項目の更新形式
「A=値更新」、「D=差分更新」のご紹介ありがとうございます。
いまだ試した事がありませんが試してみます。dbMAGIC V8 + Pervasiveの頃ってトランザクション開始とか
レコードロックが残るとか何も考えずに作っておりました。SQL Serverを使い始めてから、なんでレコードロック解除待ちが
出るか意味もわからず。周りも皆最初はそんな状態でした。トランザクション開始、コミットを意識するようになりましたが、
デッドロックが実際に起きているシーンを沢山お客様から聞いた事もなく、
最近まであまり意識した事もありませんでした。私はバッチ処理は、大抵がP=物理、トランザクション開始 T=タスク前の前
にしております。そのバッチ処理が終えるまで、レコードロック状態が
残る訳ですもんね。知人は、ほとんどトランザクション開始を P=レコード前の前にしているようでした。
私の伝票入力処理の作りは、伝票修正時は、
既存のその売上明細データを10明細とか削除して、
商品月間情報も売上数量を減して、その後、メモリWの内容でSQL Serverへ売上明細をINSERTしているような
処理にしています。
同時に商品月間情報も売上数量を加算しています。私はタスク前トランザクション開始にしているので、
複数端末で伝票保存する場合、稀に
商品月間情報でデッドロックが起きていやしないかと気になる連絡が
ありました。伝票新規登録時の伝票番号採番管理データもレコードロック解除待ち
になりがちなので、それはトランザクション外に置いて、
そのレコードロックは解除されるようしております。
とりあえずまずは伝票保存時
・タスク前トランザクションのまま
・デッドロックを起こす再現実験をしてみます。 -
お客様のmgerror.logの
レコードロック解除待ちです.データソース:・・・・をまず確認してみます。
-
1日 10時間位稼働で1日 6,000売上明細行のお客様のmgerror.logを覗いてみました。
<74482206123556192> 26/06/2020 10:44:21.533 [Error ] - レコードロック解除待ちです.データソース: DATA商品月間, program: 売上伝票入力(一般).保存バッチ.商品月間D連鎖更新. S[連鎖更新]商品月間D
<266541349524965440> 26/06/2020 10:44:18.636 [Error ] - レコードロック解除待ちです.データソース: DATA商品月間, program: 売上伝票入力(一般).保存バッチ.商品月間D連鎖更新. S[連鎖更新]商品月間D
といったのが100行ぐらい連続しているのが見つかりました。
1箇所だけですが。デッドロックしている所だと思われます。[連鎖更新]商品月間Dというバッチタスクは、拠点別 商品コード別 年月別 月間集計情報で
前月残~売上数量等の集計~当月残などを保持しているデータです。在庫数を数珠繋ぎ更新しているデータですね。
-
このようなテーブルの構成だと伝票単位の更新ではなく明細毎にしないと問題は発生しますね
昔は集計ファイル等を持ちましたがSQLになってからは持たなくなりましたね・・・
-
ishijimaさんありがとうございます。
売上数や出荷数の月間集計ファイルを持たぬ場合、例えば年次で開始数を持つとか、そんな作りもありなのでしょうね。
今までは、販売管理には得意先月間情報、仕入先月間情報、商品月間情報など用意する作りばかりでした。 -
昔は私も集計テーブルを作成していました。
ただSQLの場合SQL文でいろいろな事ができるで集計ファイルを作成しなくなりました。
スピードも問題ないので・・
-
統計の為の集計ファイルという側面も確かにありますが、主の存在意義は残高の保持、残数の保持でしょうね。
-
こんにちはPuです
一旦メモリーワークで入力し、その後実テーブルに書き出すと言う動作は
遅延トランとほぼ同じ動作ですよ。(データセットが同じ仕組みなので)
ただ競合の仕組みを自前で組み込まないといけませんが
遅延トランはそのような仕組みをメモリーワークを使わなくてもできる(内部的にはメモリーワークを使用している)
遅延トランは競合の仕組みをレコード単位、項目単位と細かな設定がノンプログラミングで出来る
と言うメリットがある。
WEBマージアプリを作成する場合、遅延と同じ仕組みが必要になるので
競合(更新前に他のユーザーが書き換えしていないか確認する必要があるので)
そういうロジックうを良く組み込みました。
でわ~でわ~
-
Puさん、ありがとうございます。
WEBなど、
排他やレコードロックなどが無い場合は
、呼出し前のそのレコードの更新日時と、
保存しようとした時のそのデータの現在の更新日時を比べるとか
更新回数カウントを比べるなど、自前で構築するのでしょうね。 -
Puさん アドバイスありがとうございます。
遅延トランは全然使った事が無いので、私もやってないといけません。
昨日のユーザーとは別のユーザーのmgerror.logを見てみました。
同じ仕入先で仕入伝票を入力し、別な人は1~2ケ月前の仕入伝票などを入力保存
などとした場合、おそらく仕入先別 年月別 買掛金などを保持するデータで
デッドロックを起こしていそうなエラーログも見つかりました。
私の作りは、1枚の伝票を二人同時には編集出来ないので、その点では
問題はありません。伝票新規登録、変更、削除の時に
・得意先月間情報
・仕入先月間情報
・商品月間情報
これらへの更新時に、バッティングするので
その部分だけを、WRNモードでオープンするのも有りなのかもしれません。ちなみにWRNオープンは全く使っておりません。
クラサバです。
バッチ処理でデッドロックが生じないように
P=物理
L=レコードロック時
I=即時
にすれば、1件処理する都度、ロック情報も消えるのでしょうね。
メモリWで編集して、保存実行時に一括更新バッチ処理をする作りをよく採用しており
鑑情報をごっそり変える作りが容易だと思っています。でもこれは私の固定概念ですので、また別な作りも優れている点があるでしょうね。
-
Pervasiveの物理トランザクションしかなかった頃は、ワークファイルを使って処理する方法を用いていた方が多かったようですが、遅延トランザクション機能がリリースされてからは、ほかの皆さんも言われているように、遅延自体をワークにするという手法がメジャーになってきました。この方がプログラムの作成も楽ですし、無用のトラブルを避けることもできますよ。
-
tandaさんありがとうございます。
クラサバですが新規の分は遅延トランザクションも検討します。
入力済の伝票を呼び出して、明細を数行削除して、数行追加。
トランザクション終わる時に、
それらの更新作業がいっきに物理トランのように動く訳ですもんね。私がやってるメモリW編集方式では、1明細の変更であっても、
伝票修正保存時、既存明細を全部消して、
メモリWの全レコードを実データへINSERTしている作りにしています。
負荷は大きいと言えますね。明細レコードには、商品コード+日付といったインデックスも用意してありますし。
遅延トランを用いて鑑は変数+明細は実データとか、鑑も実データとか
もありなのでしょうね。社内にあるので、某RIAソフト、某PKGも参考にしたいと思います。
-
今までは既存レコードを「変更」で開いたと同時に伝票排他情報を作るようにしておりました。
(入力時ロックは使用しておらず、作りこんでおりました。マスタメンテ等は入力時ロック。)
それは無しにして、とりあえず照会モードで伝票を閲覧。ファンクションキーで修正モードへ。
Lock情報を作り、誰がLockしているかわかるよう、伝票毎に編集者ログも記録する
なんて事を次期目指したいと思います。
-
メモリW編集 物理トランの場合、
保存を指示してからデータベース更新処理を稼働させる。遅延トランの場合、明細入力しながら(実際に物理データに書き込みはしないが)
物理データへの更新処理を実施する。遅延トランで、その伝票への一切の変更を止めたい!
という時は、Rollbackさせるのでしょうね。多分。MSJさんの遅延トランザクションの資料も拝見したいと思います。
あるRIAのソフトを拝見しましたが
明細メモリWから
明細実データへバッチ書込みをしておりました。伝票修正時は、事前に明細実データをDELETEを済ませるようでした。
ちょっと思っていた遅延トランの作りとは違っていました。
売上明細の入力中も
売上明細のバッチ実データへのINSERT時も
在庫データへの更新もしていませんでした。
在庫データは、毎月更新をして、本日理論在庫を求める時は
前月残+SUM(当月入庫数)-SUM(当月出庫数)のSQL実行
といった作りがベターなんですかね。 -
商品検索画面に、在庫数も一緒に表示してくれといった需要もありますし。
遅延トランの時は、1明細入力したら、商品コード+倉庫+年月の集計データを
更新するのも有りなんでしょうね。 -
某クラサバ販売管理PKGもメモリWで編集して、伝票修正時は
実データを全DELETEして、商品月間情報減して、数珠繋ぎ更新をし、
メモリWで実データへ全INSERTして、商品月間情報へ加算、
数珠つなぎ更新をしていました。また参考になる物を探してみたいと思います。
というかこれ以上は持っていないと思うので、試行錯誤してみたいと思います。
-
見たわけではありませんが、今出ているパッケージ商品群はトランザクション処理がメジャーになっていると思いますよ。
昔のdbMAGICの頃の商品群は、COBOLの手法がそのまま使われているものが多かったように思います。
-
tandaさん、そうでしょうね。
ちなみに某RIAは、xpa3.1を想定した分で、2016年7月版でした。某販売管理は大手老舗PKGで2018年7月版でした。
↑追記)これはxpa3.2でした。
-
そうですね、dbMAGICの頃からのコンバージョンが多いみたいです。
-
PuさんやISHIJIMAさんが推奨されているような、合理的なトランザクションを組み込んだパッケージは、まだまだ少ないのかもしれませんね。
-
そういった意味でも、マジック社主催の「RIAトレーニング3日間」は、遅延トランザクションの解説に大幅なページを割いた、最新のテクノロジ提供媒体だと思います。
-
ちなみに、私の連載でも書いていますが、遅延トランザクションはWebClientでも完璧に動作します。これを検証したときは感動ものでした!
-
こんにちはPuです。
nkmtさん、なにか話の根幹がずれて来てるような
前も遅延トラン(magicの世界の言葉:一般的には楽観的ロック)の話がありました。
データベースのロックを出来るだけ発生させない仕組みですよ。
webの世界では画面を開きっぱなし、かつ大量のユーザーがアクセスするので
従来のようなトランザクションロックではロックされる確率が高いので
楽観的ロックと言う手法が出てきたのです。
業務上悲観的ロックも必要な場合もありますので。
でわ~でわ~
-
Puさん、tandaさん、ISHIJIMAさん お世話になっております。
遅延トランの話は前も頂きました。
まだ使うに至っておりません。
申し訳ないです。私のメモリWで編集して、いっきに実データへ書き込むのも
出来るだけロック時間を短くするという方式ではあるんでしょうけど
1明細の変更でも、複数行分のデータの書き込みをするので
勿体ない伝票入力処理かもなというのを認識しました。
物理トラン、タスク前トランザクション開始、R=復旧の
バッチで、デッドロックが起きる実験をしました。
オンラインタスクを並行実行で2本実行。(別コンテキスト)そこからそれぞれ以下のバッチ更新処理を実行。
片や 担当者マスタを1番、2番、3番~100番まで昇順呼出しで書き換え。
片や 担当者マスタを100番、99番、98番~1番まで降順呼出しで書き換え。
どちらも画面で分かり易いよに、レコード毎に1秒のDelayをいれました。更新バッチをラインモードで画面に表示。
途中で両者がデッドロックになるのがよくわかりました。
同じタイミングで実行すれば、50番前後でデッドロックが生じました。こんなにちゃんと再現実験をしたのは初めてでした。
物理トラン、タスク前トランザクション開始、R=復旧
またそのタスクが1からリランするのも体験出来ました。
しかしデッドロックが生じると、
両者のバッチが最初からやり直しになり、永遠に終わらないのも確認しました。R=復旧 はほとんど使った事がありません。
ISHIJIMAさんも最初提示して頂きましたが
タスク前トランザクション開始 ではなく
レコード毎のトランザクションにした所、デッドロックは回避出来ました。
私はバッチ処理は
物理トラン、タスク前トランザクション開始、A=アボートにする事が
多かったのですが、それらは物によっては、レコード毎ロックに
した方がいい物もありそうです。
サインインしてコメントを残してください。
コメント
33件のコメント