mysql の楽観的ロックは悲観的ロックに関連しています。楽観的ロックは、通常の状況ではデータが競合を引き起こさないことを前提としているため、データが更新のために送信されると、データの競合が正式に検出されます。競合が見つかると、エラー情報がユーザーに返され、ユーザーは何をすべきかを決定できます。
mysql の楽観的ロックは (楽観的ロック) 悲観的ロックと比較して、楽観的ロックはデータが一般に競合を引き起こさないことを前提としているため、データが更新のために送信されると、データの競合が正式に検出され、競合が見つかった場合はエラー メッセージがユーザーに返され、ユーザーが何をすべきかを決定できるようになります。
それでは、オプティミスティック ロックをどのように実装すればよいでしょうか? 一般的に、次の 2 つの方法があります:
1. データ バージョン (バージョン) 記録メカニズムを使用して、 を実現します。楽観的 ロックの最も一般的に使用される実装方法の 1 つ。データバージョンとは何ですか?つまり、通常は数値の「バージョン」フィールドをデータベース テーブルに追加することによって、データにバージョン識別子を追加します。データを読み込む際には、バージョンフィールドの値も合わせて読み出し、データが更新されるたびにバージョン値が1ずつインクリメントされます。
アップデートを送信すると、データベーステーブルの該当レコードの現在のバージョン情報を判断し、初めて取り出したバージョン値と比較します。初めて取り出したバージョン値と比較し、等しい場合は更新され、そうでない場合は期限切れデータとみなされます。次の図を使用して説明します。
上の図に示すように、更新操作が順番に実行されると、データのバージョン (バージョン) は競合することなく順番に増加します。ただし、異なる業務が同じバージョンのデータを変更した場合、最初に送信された操作 (図の B) はデータのバージョンを 2 に更新します。B の後に A が更新を送信すると、データのバージョンが変更されたことがわかります。 . の場合、A の更新操作は失敗します。
2. オプティミスティック ロックの 2 番目の実装方法は、最初の実装方法と似ています。また、オプティミスティック ロック制御を必要とするフィールドをテーブルに追加します。 . 、名前は重要ではありません。フィールド タイプは、上記のバージョンと同様のタイムスタンプを使用します。更新が送信されると、現在のデータベース内のデータのタイムスタンプがチェックされ、更新前に取得されたタイムスタンプと比較されます。一貫性がある場合は OK、そうでない場合はバージョンの競合です。
関連する学習の推奨事項: mysql ビデオ チュートリアル
##使用例:
MySQL を使用した場合InnoDB例として 前の例を見てみましょう: 商品テーブルにフィールド ステータスがあります。ステータス 1 は製品が注文されていないことを意味し、ステータス 2 は製品が注文されていないことを意味します。次に、特定の商品を注文するときは、商品のステータスが 1 であることを確認する必要があります。プロダクト ID が 1 であるとします。
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> select * from t_goods;
+----+--------+------+---------+
| id | status | name | version |
+----+--------+------+---------+
| 1 | 1 | 道具 | 1 |
| 2 | 2 | 装备 | 2 |
+----+--------+------+---------+
2 rows in set
mysql></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> select * from t_goods;
+----+--------+------+---------+
| id | status | name | version |
+----+--------+------+---------+
| 1 | 2 | 道具 | 2 |
| 2 | 2 | 装备 | 2 |
+----+--------+------+---------+
2 rows in set
mysql></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 サイトの他の関連記事を参照してください。