最近のアップグレード中小規模ビジネスパートナーがあり、このような問題に遭遇した、我々は、ユーザーがアップグレードを手動で同期をトリガすることをユーザに要求元のアカウント経由でデータを同期した後に適用する必要があり、新しいアカウントシステムを設計していますデータの一部がローカルユーザーに居住しているため、同期するためのボタン。ネットワークの問題なぜならば、そして、この過程で問題があり、ユーザがダブルクリックするボタンがどのように行うには?我々はいくつかのクライアントプロセスを作ったとしても、同期中に、もう一度クリックしますが、私の最近の練習の爬虫類の後、他の誰かが私たちのインターフェースをキャッチした場合、それはまだ安全ではないことはできません。
このビジネスシナリオに基づいて、私が使用します第2の要求を開始することができない、ユーザの要求に時間を制限、Redisのロックされた道を。
我々は、要求がロックオブジェクトを取得しようとすることが好ましく、このロックオブジェクトへの鍵は、実際にユーザーIDです入力した後、取得が成功した場合、当社はユーザーの時間を決定した場合、同期化されている場合は、ユーザーが同期されたプロンプトを表示するために直接戻ることができ、データを同期化されていますメソッドを入力した後に取得場合は、直接データを同期するために、ビジネスロジックの実行、そして最終的にロックを解除し、ロックが失敗し、それは最初の時間は、要求が終わっていない可能性があり、その後、彼らは要求を立ち上げていないので、この時点では得ることですロック未満、全く同期同期データが表示され、数回発生もないでしょう。
したがって、この需要とした後、私たちは、次のコードを実装し、このRedisのを使用する必要があります。まず第一に私たちはRedisの方法を紹介したいことを知っておく必要があります。
保存が成功した後の要素が既にRedisのインスタンスに存在するのであれば、我々はそれはRedisの中で一意である必要があり、Redisのロックオブジェクトを持つユーザーのみをしたい、とカバーされるべきではない、この方法では、trueを返しますその後、ダイレクトリターン偽
setIfAbsent(キー、値)
ロックオブジェクトを取得した後、私たちのサービスがハングアップした場合でも、真ん中と問題があるが、その後、別の要求今回はこのような状況の考慮に基づいて、ロックを取得し、我々はまた、有効期限に要素を追加する必要があり、確かではありません時間、の出現後に当社のサービスをハング防ぐデッドロックの問題。
/ ** *添加元素 * * @paramキー * @param値 * / 公共ボイドSET(オブジェクトキー、オブジェクト値){ IF(== NULL || Keyの値== NULL){ リターン; } redisTemplate.opsForValue() .SET(キー、value.toString()); } / ** *すでにfalseを返したが存在する場合は、そうでない場合はtrueに返す * * @paramキー * @param値 * @return * / パブリックブールSETNX(オブジェクトキー、オブジェクトの値が、 expireTimeロング、TimeUnitでmimeUnit){ IF(== NULL || Keyの値== NULL){ falseに戻ります。 } 。redisTemplate.opsForValue()setIfAbsent(キー、値、expireTime、mimeUnit)を返します。 } / ** *获取数据 * * @paramキー * @return * / パブリックオブジェクトGET(オブジェクトキー){ IF(キー==ヌル){ 戻りヌル。 } 。redisTemplate.opsForValue()を返す(キー)を取得します。 } / ** *删除 * * @paramキー * @return * / パブリックブールのremove(オブジェクトキー){ (キー==ヌル)の場合{ falseを返します。 } redisTemplate.delete(キー)を返します。 } / ** *加锁 * * @Paramキー * WAITTIMEの待ち時間@param * @param expireTime有効期限 * / パブリックブール・ロック(文字列キー、WAITTIMEロング、ロングexpireTime){ String値= UUID.randomUUID()のtoString()でReplaceAll(「。。 - ""「).toLowerCase(); フラグ= SETNX(キー、値、expireTime、TimeUnit.MILLISECONDS)のboolean; //ロックを取得するための成功した試みを返す (フラグに){IF フラグに戻り; }他{ //取得失敗 //今の時間 ロングNEWTIME =にSystem.currentTimeMillis(); //有効期限を待つ 長いloseTime = NEWTIME + WAITTIME。 //ロック成功リターン獲得しようとし続けて * @paramキー 一方(のSystem.currentTimeMillis()<loseTime){ ブールtestFlag = setNx(キー、値、expireTime、TimeUnit.MILLISECONDS)。 (testFlag)場合{ testFlagを返します。 } {試みる のThread.sleep(1000)。 }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } } } falseを返します。 } / ** *释放锁 * * @return * / 公共ブールUNLOCK(オブジェクトキー){ リターンのremove(キー); }
当社全体のロックコードのロジックは、我々が分析し、終了している、ユーザーが最初の呼び出しのロックロックを取得しようとすると、ロック、ロック()メソッドが取る3つのパラメータは後に来た:キー、WAITTIMEユーザーが取得された場合ロック未満、あなたが最後のパラメータを待たないであろう、この時間は、ロックの期限が切れた後、サービスの後にハングアップ防止どのくらいですずっと後に待つことができ、デッドロックが発生します。
ロックが成功した場合、ロック操作を実行するために、)(ロックを入力した後、trueを返すロックを取得することに失敗した場合、その後、私たちの背後にあるビジネスロジックを実行、現在の時刻と現在の時刻を加えた有効期限のセットを取得待機時間が経過するまでロックを取得するために再度試して、その後、内部の時間を待っている場合は、比較してください。
注:設定では、我々はデッドロックの有効期限を防ぐために設定し、我々は注意を払う必要があります。このプロセスはアトミック操作ではありませんので、あなただけ正常に設定して、成功した後に有効期限を設定する要素のセットに移動するのを待つことはありませんその後、これに成功し、直接サービスにリンクされ、有効期限を設定するので、この時間は、それが起こるのだろうないデッドロックの問題を、私たちはその記憶素子を確保し、それがアトミックである必要があります有効期限を設定する必要があります。
最後に、我々はテストするためのテストクラスを書きます
公共のボイドTEST01 @Test(){ 文字列のキーは= "UID:12011"; ブールフラグ= redisUtil.lock(キー、10L、1000L * 60); IF(フラグ!){ //ロックの失敗を取得 System.err.printlnを( ;) "失敗をロックゲット" {他} //成功したロック獲得 ; System.out.printlnは( "買収の成功をロック") } //リリースロック ; redisUtil.unLock(キー) }