楽観的な排他制御
データベースを利用する際に、同じデータを同時期に複数の端末から変更(削除)する場合を考えておく必要があります。
データベースの排他制御、または、長時間トランザクションと呼ばれる処理です。
排他制御には、楽観的制御と悲観的制御がありますが、練習プログラムでは、簡単に実装できる楽観的排他制御を用いています。
具体的には、データ構造に「更新回数」というカラムを作り、
CREATE TABLE `sightseeing` (
`ID` int(10) UNSIGNED NOT NULL,
-- (中略)
`登録日` date NOT NULL DEFAULT current_timestamp(),
`更新日時` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`更新回数` int(10) UNSIGNED NOT NULL DEFAULT 0
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='高山市の観光施設:オープンデータ';
更新フォームに、更新回数のタグを用意し、
<tr>
<th>更新回数</th>
<td><input type="text" name="version" readonly value="0"></td>
</tr>
「更新回数」の名前は version です。
サーバーから情報を得たときと更新回数が変化していなければ、データの更新を行うようにしています。
@router.put('/update_institution')
def update_institution(ID:int=Form() , name:str=Form() , kana:str=Form() , addr:str=Form() , exp:str=Form(None) , url:str=Form(None) , note:str=Form(None) , version:int=Form()):
'''指定されたデータを更新する
(中略)
'''
conn = mydb.connect(**config.database)
cur = conn.cursor(dictionary=True)
sql = ("UPDATE `sightseeing` SET "
"`名称` = %s , "
"`名称_カナ` = %s , "
"`住所` = %s , "
"`説明` = %s , "
"`URL` = %s , "
"`備考` = %s , "
"`更新回数` = `更新回数` + 1 "
"WHERE (`ID` = %s) AND (`更新回数` = %s) " )
param = (name , kana , addr , exp , url , note , ID , version)
cur.execute(sql , param)
# (中略)
return HTMLResponse(content)
プログラムでは、更新回数
= 更新回数
+ 1 として、更新に成功すれば、更新回数を上げるようにもしています。
また、readonly属性を付けて、編集不可にしています。
type="hidden"として、ユーザーに見せなくても良いかもしれません。
更新の判断について
MySQLには、ON UPDATE current_timestamp()という属性があるので、以前は、更新日時を更新されたかどうかの判断に使っていました。
データが更新されれば、MySQLが自動的に日時を変更してくれるので便利です。
しかし、日時では不具合があるという記事を読んだので、「更新回数」を使うようにしました。
関連記事一覧
htmxを使ってみた-(1)htmxの基本-
htmxを使ってみた-(2)準備-
htmxを使ってみた-(3)ルート関数-
htmxを使ってみた-(4)htmxを使う-
htmxを使ってみた-(5)HTMLのdialog-
htmxを使ってみた-(6)データの表示-
htmxを使ってみた-(7)データ追加-
htmxを使ってみた-(8)要素の変更-
htmxを使ってみた-(9)ページの再読み込み-
htmxを使ってみた-(10)データの変更-
htmxを使ってみた-(11)データベースの排他制御-
htmxを使ってみた-(12)確認ダイアローグ-
htmxを使ってみた-(13)データ削除-(最終)