ホームページ >データベース >mysql チュートリアル >mysqlのオプティミスティックロックとは何ですか?

mysqlのオプティミスティックロックとは何ですか?

coldplay.xixi
coldplay.xixiオリジナル
2020-06-29 15:56:424790ブラウズ

mysql の楽観的ロックは悲観的ロックに関連しています。楽観的ロックは、通常の状況ではデータが競合を引き起こさないことを前提としているため、データが更新のために送信されると、データの競合が正式に検出されます。競合が見つかると、エラー情報がユーザーに返され、ユーザーは何をすべきかを決定できます。

mysqlのオプティミスティックロックとは何ですか?

mysql の楽観的ロックは (楽観的ロック) 悲観的ロックと比較して、楽観的ロックはデータが一般に競合を引き起こさないことを前提としているため、データが更新のために送信されると、データの競合が正式に検出され、競合が見つかった場合はエラー メッセージがユーザーに返され、ユーザーが何をすべきかを決定できるようになります。

それでは、オプティミスティック ロックをどのように実装すればよいでしょうか? 一般的に、次の 2 つの方法があります:

1. データ バージョン (バージョン) 記録メカニズムを使用して、 を実現します。楽観的 ロックの最も一般的に使用される実装方法の 1 つ。データバージョンとは何ですか?つまり、通常は数値の「バージョン」フィールドをデータベース テーブルに追加することによって、データにバージョン識別子を追加します。データを読み込む際には、バージョンフィールドの値も合わせて読み出し、データが更新されるたびにバージョン値が1ずつインクリメントされます。

アップデートを送信すると、データベーステーブルの該当レコードの現在のバージョン情報を判断し、初めて取り出したバージョン値と比較します。初めて取り出したバージョン値と比較し、等しい場合は更新され、そうでない場合は期限切れデータとみなされます。次の図を使用して説明します。

mysqlのオプティミスティックロックとは何ですか?

上の図に示すように、更新操作が順番に実行されると、データのバージョン (バージョン) は競合することなく順番に増加します。ただし、異なる業務が同じバージョンのデータを変更した場合、最初に送信された操作 (図の B) はデータのバージョンを 2 に更新します。B の後に A が更新を送信すると、データのバージョンが変更されたことがわかります。 . の場合、A の更新操作は失敗します。

2. オプティミスティック ロックの 2 番目の実装方法は、最初の実装方法と似ています。また、オプティミスティック ロック制御を必要とするフィールドをテーブルに追加します。 . 、名前は重要ではありません。フィールド タイプは、上記のバージョンと同様のタイムスタンプを使用します。更新が送信されると、現在のデータベース内のデータのタイムスタンプがチェックされ、更新前に取得されたタイムスタンプと比較されます。一貫性がある場合は OK、そうでない場合はバージョンの競合です。

関連する学習の推奨事項: mysql ビデオ チュートリアル

##使用例:

MySQL を使用した場合InnoDB

例として 前の例を見てみましょう: 商品テーブルにフィールド ステータスがあります。ステータス 1 は製品が注文されていないことを意味し、ステータス 2 は製品が注文されていないことを意味します。次に、特定の商品を注文するときは、商品のステータスが 1 であることを確認する必要があります。プロダクト ID が 1 であるとします。

注文操作には 3 つのステップが含まれます:

1. 製品情報のクエリ

select (status,status,version) from t_goods where id=#{id}

2. 製品情報に基づいて注文を生成

3. 製品ステータスを 2

update t_goods 
set status=2,version=version+1
where id=#{id} and version=#{version};

に変更します

オプティミスティック ロックを使用するには、まず t_goods テーブルを変更し、バージョン フィールドを追加します。データは1です。

t_goods

テーブルの初期データは次のとおりです。 <pre class="brush:php;toolbar:false">mysql&gt; select * from t_goods; +----+--------+------+---------+ | id | status | name | version | +----+--------+------+---------+ | 1 | 1 | 道具 | 1 | | 2 | 2 | 装备 | 2 | +----+--------+------+---------+ 2 rows in set mysql&gt;</pre>楽観的ロックの実装には、次のように練習用に MyBatis を使用します。

## 商品エンティティ クラス:

/** 
 * ClassName: Goods <br/> 
 * Function: 商品实体. <br/> 
 * date: 2013-5-8 上午09:16:19 <br/> 
 * @author chenzhou1025@126.com 
 */  
public class Goods implements Serializable {  
  
    /** 
     * serialVersionUID:序列化ID. 
     */  
    private static final long serialVersionUID = 6803791908148880587L;  
      
    /** 
     * id:主键id. 
     */  
    private int id;  
      
    /** 
     * status:商品状态:1未下单、2已下单. 
     */  
    private int status;  
      
    /** 
     * name:商品名称. 
     */  
    private String name;  
      
    /** 
     * version:商品数据版本号. 
     */  
    private int version;  
      
    @Override  
    public String toString(){  
        return "good id:"+id+",goods status:"+status+",goods name:"+name+",goods version:"+version;  
    }  
  
    //setter and getter  
  
}

GoodsDao

/** 
 * updateGoodsUseCAS:使用CAS(Compare and set)更新商品信息. <br/> 
 * 
 * @author chenzhou1025@126.com 
 * @param goods 商品对象 
 * @return 影响的行数 
 */  
int updateGoodsUseCAS(Goods goods);

mapper.xml

<update id="updateGoodsUseCAS" parameterType="Goods">  
    <![CDATA[ 
        update t_goods 
        set status=#{status},name=#{name},version=version+1 
        where id=#{id} and version=#{version} 
    ]]>  
</update>

GoodsDaoTest テスト クラス

@Test  
public void goodsDaoTest(){  
    int goodsId = 1;  
    //根据相同的id查询出商品信息,赋给2个对象  
    Goods goods1 = this.goodsDao.getGoodsById(goodsId);  
    Goods goods2 = this.goodsDao.getGoodsById(goodsId);  
      
    //打印当前商品信息  
    System.out.println(goods1);  
    System.out.println(goods2);  
      
    //更新商品信息1  
    goods1.setStatus(2);//修改status为2  
    int updateResult1 = this.goodsDao.updateGoodsUseCAS(goods1);  
    System.out.println("修改商品信息1"+(updateResult1==1?"成功":"失败"));  
      
    //更新商品信息2  
    goods1.setStatus(2);//修改status为2  
    int updateResult2 = this.goodsDao.updateGoodsUseCAS(goods1);  
    System.out.println("修改商品信息2"+(updateResult2==1?"成功":"失败"));  
}

出力結果:

good id:1,goods status:1,goods name:道具,goods version:1  
good id:1,goods status:1,goods name:道具,goods version:1  
修改商品信息1成功  
修改商品信息2失败

説明:

GoodsDaoTest テスト メソッド内また、同じバージョンのデータが異なる商品オブジェクトに割り当てられており、good1 オブジェクトが最初に変更されてから更新操作が実行され、実行が成功したこともわかりました。次に、goods2 を変更し、更新操作を実行すると、操作が失敗したことを示すメッセージが表示されます。この時点で、

t_goods

テーブルのデータは次のとおりです。 <pre class="brush:php;toolbar:false">mysql&gt; select * from t_goods; +----+--------+------+---------+ | id | status | name | version | +----+--------+------+---------+ | 1 | 2 | 道具 | 2 | | 2 | 2 | 装备 | 2 | +----+--------+------+---------+ 2 rows in set mysql&gt;</pre> 最初の更新時に、ID 1 のデータ バージョンが 2 に変更されたことがわかります。したがって、good2 を更新すると、条件が一致しない更新が行われるため、更新は成功しません。具体的な SQL は次のとおりです: <pre class="brush:php;toolbar:false">update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};</pre> このようにして、楽観的ロックを実現しました。

以上がmysqlのオプティミスティックロックとは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。