Q&A

回答の並べ替え:
投稿新規に質問を投稿する

画面の同時更新対応(画面排他)

kin-taro kin-taro

2019-06-26 19:03

CELFでとあるマスタのメンテナンス画面を作成しています。
アプリを起動すると登録されているマスタ名の一覧が表示されて
各行に「詳細」ボタンを設けてその詳細をメンテナンスするようにしています。
ここで問題となるのが同時に違うユーザが同じマスタを更新した際に後勝ちとなってしまうことです。
対応として、排他テーブルを別途作成して「詳細」ボタンをクリックしたときに
排他テーブルにユーザ情報を登録することで対象のマスタが誰かによってメンテナンスされているかどうかを判断させています。
ただ、今度は登録した排他テーブルの情報を削除するタイミングが難しく、
マスタの詳細画面を閉じたときに排他テーブルのレコードを削除するアクションを作ってはいるのですが画面右上の「×」から画面を閉じた場合にはアクションを設定することができないため排他テーブルのメンテナンス画面を別に用意して無駄なレコードが残った場合はそこから削除するような運用を行っています。。
何かよい対応策はありますでしょうか。皆さまは画面同時更新の際の後勝ちに対してどのような対処を行っていますでしょうか。

kin-taro kin-taro
ご回答ありがとうございます。

おっしゃられる通り、レコードにステータスを設けるなど様々な対応が考えられますね。
そもそも1つの画面で複数の情報を表示させ、それを複数の人でメンテナンスするような画面設計が悪いのかもしれません。。
弊社ではExcel→CELFの業務移行を実施している状況で、可能な限りExcelに近い画面でユーザに提供を考えているため、その辺りから考え直すことも検討します。
ただ、画面の「×」でシートを閉じたときのアクションは標準で実装していただきたいものです。
Yexiongmao Yexiongmao
遅い投稿ですいません。
マスタデータ更新の排他制御については、ユースケースはいろいろあると思います。
詳細ボタンを押して、その詳細をメンテナンスするのであれば、1件づつ画面でデータを確認して更新ボタンを押すようなデザインではいけないのでしょうか?
それなら、(株)コサウェル様の最初の楽観ロックでも滅多にエラーは起きないと思います。
複数レコードをメンテナンスしてチェックリストを出してOKなら更新するというようなデザインにするなら、テーブルにユーザIDとステータスの項目を追加して、
10入力中、20チェックリスト出力、などレコードのステータスを定義して、対象レコードのステータスIDを更新しておきます。新規に取得できるレコードのステータスIDを限定しておけば悲観ロックを掛けた状態になり他者からの更新は防げます。途中で画面を閉じてしまったとしても、同じユーザIDで画面を開いた時に閉じた時の状況を復元し、ステータスを進められるようにしておけば良いと思います。
人が入力してチェックして更新できる程度のレコード数でしたら、「データ更新を一括実行する」アクションを使えば、トランザクションの発生から、コミットまでやってくれるので、処理に時間がかかるということはありません。
テーブルのレコード数もあまり関係ありません。
テーブルレコード全件に悲観ロックを掛ける手段はあるでしょうが、アプリの使い勝手が格段に悪くなる上に、データ破損の危険性も高まると思います。
kin-taro kin-taro
コサウェル様

回答ありがとうございます。

いただいた回答で対応も考えたのですが、結局データの更新時にしかチェックが出来ないというのが今のところですかね。。
複数人が同時に画面を開いたときに一番最初にデータを更新した方だけが有効になり、それ以外の方はエラーとなってしまうと「それ以外」の方が修正したデータ&時間が無駄になってしまうことは許容できないところなので、今の運用を続けようと思います。
いつかどこかでシートを閉じたときのアクションを設定出来たり、画面排他機能が標準で用意されることを期待します!
あと、、コメントを記載する際に元のコメントが見えないので元のコメントが見える状態で新しくコメント記入ができるようにしてもらいたいですね(笑)
株式会社 コサウェル 株式会社 コサウェル パートナー
メダルベストアンサー
対象データが複数件の場合だと確かに悩みますね。
それでは、以下のように楽観的排他制御をアクションで
実現してみるのはどうでしょうか。

[1] 画面を開いたときに、対象データの件数と最大の LAST_MODIFIED を
  取得し(※)、セル等にセットしておく
  ※データ集計アクションやSQLアクション(導入していれば)で実現できます
[2] 更新時にもう一度対象データの件数と最大の LAST_MODIFIED の値を取得する
[3] 上記[1]と[2]で取得した件数と LAST_MODIFIED の値を比較し、
  どちらか一方でも異なる場合は排他エラーと判断する

件数が異なる場合は登録or削除が他のユーザによって行われ、
LAST_MODIFIED が異なる場合は登録or更新が行われたと判断できます。
また、このような形であれば「×」で閉じた場合でも対応できるかと思います。
メールコンタクトをとる
kin-taro kin-taro
コサウェル様

回答ありがとうございます。
ちょっと私のQAの文面が悪かったかもしれません、、
確かにレコード排他であれば対応が可能かと思います。ただ、1つの画面から複数のデータを更新する場合、1つ1つのレコードに対して更新を行ってしまうと処理時間がかかることやリソースも多く取られてしまうため一括更新を行っている状況です。
※一括更新は複数の対象レコードをCSVで出力してテーブルをDelete→Insertで行っています。
例えばCELFのサンプルアプリの「予算実績管理」で予算入力画面を同時に開いたときにデータの更新KEY(年度、組織)が同じ場合は後勝ちになってしまうと思います。
サンプルアプリでは行ごとの更新を実施しているのでデータ排他が有効になるかと思いますが、対象行が10,000行あった場合は更新にものすごい時間がかかってしまうと思います。そこで弊社では一括更新をしているので画面排他を無理やり実施している状況です。
何か良い手はないものでしょうか。。
株式会社 コサウェル 株式会社 コサウェル パートナー
パートナーの株式会社コサウェルと申します。

データの排他制御という観点ですと、「テーブルのデータを更新する」アクションを使っているかと思いますが、排他制御を使っていただければよいかと思います。

検索時(データ更新前)にIDと更新日をどこかのセルに設定しておきます。
テーブルのデータを更新する」アクションの「他のユーザーが更新または削除していた場合はエラーとする」にチェックを入れていただき、IDと更新日を入れたセルを設定いただき保存します。これで、登録時に排他制御ができます。
ヘルプにも排他制御について詳しく載っていますので、見てみてはいかがでしょうか?

https://cloud.celf.jp/celf-help/ja/texts/action_use/data/exclusive_control_when_table_update/exclusive_control_when_table_update.html
メールコンタクトをとる