読者です 読者をやめる 読者になる 読者になる

c4se記:さっちゃんですよ☆

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)

.。oO(此のblogは、主に音樂考察Programmingに分類されますよ。ヾ(〃l _ l)ノ゙♬♪♡

音樂はSoundCloud等バラバラの場所に公開中です。申し訳ないがlinkをたどるなどして探してください。

考察は現在は主に此のblogで公表中です。

programmingは、ひろくみせるものはGitHubで、個人的なものはBitBucketで開発中です。

c4se

DynamoDBで楽観的lockを行なふ

Programming AWS DynamoDB Python

DynamoDBにはトランザクションは無いしロック等無い。RDS使へ。好い加減にしろ。

然しDynamoDBには魅力が在るし、少々トランザクション出來なからうが此れを使ひたいといふ欲求の在る場面もある。楽観的ロック位いは出來ないだらうか。

楽観的ロックと云へば私にとってはActiveRecordのlock_versionだ。UPDATE items SET name = "New Name", lock_version = 43 WHERE id = 1 AND lock_version = 42 等のやうに、比較と更新をアトミックに行なへれば此れは實裝出來る。

DynamoDBではテーブルを跨がなければ、比較と更新がアトミックに出來る。從ってテーブルを跨がない楽観的ロックは實裝出來る。詰りテーブルを跨がないトランザクションは實裝出來る。

以下のDynamoDBテーブルが在るとする。id, name, lock_versionを持たせやう。

resource "aws_dynamodb_table" "item" {
  attribute {
    name = "id"
    type = "S"
  }
  hash_key = "id"
  name = "item"
  read_capacity = 1
  write_capacity = 1
}

記法はTerraform。

PutItem時にcondition-expressionを附けると、condition-expressionの結果が僞である時にエラーを起こし更新せぬやうに出來る。

cf. 条件式を使用した条件付きの書き込みの実行 - Amazon DynamoDB

Pythonでやると以下の如し。行が無い爲lock_version列も無い時か、或いはlock_version列が變更されてゐなければ、PutItemを實行する。

import boto3

table = boto3.resource("dynamodb").Table("item")


class Item(object):
    def __init__(id, **props):
        self.id = id
        self.name = props.get("name", None)
        self.lock_version = props.get("lock_version", 0)


def get_item(id):
    item = Item(id=id)
    res = table.get_item(
        Key={"id": id}
    )
    if "Item" in res:
        item.name = res["Item"]["name"]
        item.lock_version = res["Item"]["lock_version"]
    return item


def put_item(item):
    lock_version_attr = boto3.dynamodb.conditions.Attr("lock_version")
    table.put_item(
        Item={
            "id": item.id,
            "name": item.name,
            "lock_version": item.lock_version + 1
        },
        ConditionExpression=lock_version_attr.not_exists().__or__(lock_version_attr.eq(item.lock_version))
    )
    item.lock_version += 1

if __name__ == "__main__":
    item = get_item("mOmonga")
    item.name = "New name"
    put_item(item)

此の ConditionExpression=lock_version_attr.not_exists().__or__(lock_version_attr.eq(item.lock_version)) が条件式を組み立ててゐる。

もっと綺麗な組み立て方をしたい。