高い同時実行のPHPに対処する方法

高い同時実行でのデータセキュリティ

 

私たちは、複数のスレッドが同じファイルに書き込む際に、各の結果は、シングルスレッドの営業成績を実行する場合は、「スレッドの安全性」の問題は、(同時に同じコードを実行している複数のスレッドを表示されることを知っていると同じ、と同じ結果を期待しましたこれは、スレッドセーフ)です。

MySQLデータベースには、あなたはそれが問題を解決するための良いロック機構が付属していますが、大規模な同時シナリオで使用できる場合は、MySQLを使用することは推奨されません。スパイクやシーンをスナップ、最も重要な問題は、「スーパー」で、受注につながるこの点で制御されない場合は、出庫の実際の販売よりも多く発生しました。

ウルトラ理由の毛:

購入のシナリオを仮定し、我々は最後の最後でのみ100商品の合計を持って、我々は99品目、残り最後の1を消費しています。この時間は、システムは、スーパーその結果、これらの要求は、製品のマージンが読み込まれ、同時リクエストの複数に送信し、その後判断の残りの部分を介してです。

それは注目に値する:符号なしのフィールド番号への株式欄に覚えて、在庫がゼロの場合、符号なしのフィールドは負にすることはできませんので、falseを返します

最適化

最適化1:ライン操作をBEGINロックMySQLのトランザクションを使用して、SELECT ... FOR UPDATE; COMMIT; ROLLBACK

<?PHPの//最適化スキーム1:;関数build_order_no(){戻り日付( 'YMD')SUBSTR(内破(NULL、array_mapをMySQLのトランザクションを使用して、行ロック操作( './のmysql.php')を含みます。 ( 'ORD'、str_split(SUBSTR(uniqid()、7、13)、1)))、0、8);} //関数insertLog($イベント、$タイプ= 0){グローバルの$ CONNログ; $ SQL = "(イベント、タイプ)の値( '$イベント'、 '$タイプ')ih_logに挿入"; mysqli_query($ CONN、$ sqlを);} mysqli_query($ CONN、 "BEGIN"); //トランザクション$を開始SQL =「ih_storeどこgoods_id = 『$ goods_id』とsku_id UPDATE FOR = 『$のsku_id』から番号を選択して」;トランザクションは$ RS =をコミットした後、この時点でこのレコードがロックされている//、あなたは他のトランザクションを実行することができ待たなければなりませんmysqli_query($ CONN、$のSQL); $行= $ RS-> FETCH_ASSOC();($行[ '番号']> 0)であれば{//注文を生成$ order_sn = build_order_no(); $のSQLは=「挿入しますih_order(order_sn、USER_ID、goods_id、sku_id、価格)の値( '$のorder_sn'、 '$ user_idの'、 '$ Goods_id '' $のsku_id '' $価格「) "; $ order_rs = mysqli_query($ CONN、$のSQL); //在庫削減の$ SQL =" 更新がih_store設定数=数 -  {$番号}ここsku_id = '$のsku_id' "; $ store_rs = mysqli_query($ CONN、$のSQL);($ store_rs)であれば{エコー '在庫削減の成功'; insertLog( '在庫削減の成功'); mysqli_query($ CONN"、「COMMIT)。 //トランザクションは、そのコミット{エコー「在庫削減に失敗した」他}ロックが解除されます。insertLog(「在庫が失敗減少」);}}他{エコーの在庫は十分ではありません '; insertLogは(「在庫は十分ではありません」); mysqli_query($ CONN、「ROLLBACK 「);}COMMIT「); //トランザクションが{エコー '在庫削減が失敗した'、すなわちロック解除}他にコミットし、insertLog( '在庫が失敗減少');}}他には{エコーの在庫は十分ではありません '; insertLog( '在庫が十分ではありません'); mysqli_query($ CONN、 "ROLLBACK");}COMMIT「); //トランザクションが{エコー '在庫削減が失敗した'、すなわちロック解除}他にコミットし、insertLog( '在庫が失敗減少');}}他には{エコーの在庫は十分ではありません '; insertLog( '在庫が十分ではありません'); mysqli_query($ CONN、 "ROLLBACK");}

最適化2:ロックのアイデアをファイル

一日の訪問が大きな同時アプリケーションの数、ファイル操作の一般的な方法ではない高いかそうでないの場合は問題ありません。私たちが読んで、ファイルを操作するための複数のプロセスにおそらくファイルを書くとき、それに応じて排他的なファイルにアクセスしていない場合でも、同時高い場合、データの損失を引き起こすことは容易です。

<?PHPの//最適化シナリオ2:非ブロックファイルの排他的ロックを使用して( './mysql.php')が含ま; //は、ユニークな注文番号関数build_order_no(){返却日( 'YMD')SUBSTR(破を(生成します。 NULL、array_mapを( 'ORD'、str_split(SUBSTR(uniqid()、7、13)、1)))、0、8);} //関数insertLog($イベント、$タイプ= 0){グローバル$ログCONN; SQLは= "ih_log(イベントタイプ)の値( '$イベント'、 '$タイプ')に挿入" $; mysqli_query($のCONN、$のSQL);} $ FP =のfopen( "lock.txt"、 " W + ");(群れ($ fpは、LOCK_EX | LOCK_NB!)であれば){エコー" システムがビジー状態、後でもう一度試してください ";を返す;} //単一の$ SQLが=" ih_storeどこgoods_id =「$から番号を選択goods_id 'およびsku_idは=' $のsku_id '「; $ RS = mysqli_query($ CONN、$のSQL); $行= $ RS-> FETCH_ASSOC(); IF($行[' 番号 ']> 0){//ストック0 //単一のアナログ操作$ order_sn = build_order_no()より大きい; $のSQLは=「(ih_order挿入order_sn、USER_ID、goods_id、sku_id、価格)の値( '$のorder_sn'、 '$のuser_idを'、 '$ goods_id'、 '$のsku_id'、 '$価格')「; $ order_rs = mysqli_query($ CONN、$ sqlを); //在庫の$ SQLを減らします= $ store_rs = mysqli_query($ CONN、$のSQL);($ store_rs)場合{エコー '在庫削減の成功'; insertLog(」在庫 -  "{$数} sku_id = '$のsku_id' アップデートは、設定番号=番号ih_store"低減に成功 ')を、群れ($ fpは、LOCK_UN); //リリースロック}他{エコー' 在庫削減は失敗 '; insertLog(' 在庫削減は失敗 ');}}他{エコー' 十分な在庫 '; insertLog(' 株「十分);} fcloseを($ FP);在庫削減の成功; insertLog( '在庫の削減に成功');群れ($ fpは、LOCK_UN); //リリースロック}他{エコー '在庫削減は失敗'; insertLog( '在庫削減は' 失敗);}}他{エコー'証券十分な'; insertLog( '株十分');} fcloseを($ fpは);在庫削減の成功; insertLog( '在庫の削減に成功');群れ($ fpは、LOCK_UN); //リリースロック}他{エコー '在庫削減は失敗'; insertLog( '在庫削減は' 失敗);}}他{エコー'証券十分な'; insertLog( '株十分');} fcloseを($ fpは);

 

おすすめ

転載: www.cnblogs.com/68xi/p/11528073.html