cncml手绘网

标题: MySQL(表锁)、PHP(文件锁)锁机制及应用场景 [打印本页]

作者: admin    时间: 2022-3-17 15:53
标题: MySQL(表锁)、PHP(文件锁)锁机制及应用场景
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量
  1. C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php   // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码

. C. F3 p, b/ A5 I" V; q/ S
Mysql中的锁语法:
: Q: ^4 d8 M" T( T1 BLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
9 z9 \1 u; H! U- _/ N3 H- c& B6 vUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表- `9 g( u) V7 k5 s4 {. n- q
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞; v6 E7 K, P* }, T
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :+ l$ T+ x/ g4 ]- P
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。4 E* F( o% r  K7 q- P& m
测试时,有个文件就行,叫什么名无所谓
总结:
% K2 ~3 x1 V# H# @. G项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:- n4 h: g  z% q: R  |, G
1. 高并发下单时,减库存量时要加锁7 u: H  e5 p( a9 q
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    % T; I: [0 S! W/ ~/ i
  2.     模拟秒杀活动-- 商品100件
    7 _0 H. M8 A2 i( B9 R
  3.     CREATE TABLE ta- `0 M8 o/ ], c' T( {
  4.     (* N1 q1 B8 i9 b
  5.         id int comment '模拟100件活动商品的数量'. A* |& r. n7 x
  6.     );
    : ~& t2 \; X3 e0 Q" O8 |
  7.     INSERT INTO ta VALUES(100);* {2 l7 m$ p6 B
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件# \- D: O) d2 l. A% e) A
  9.      */ ( E, v4 K' n% x3 h/ \  U2 i$ f
  10.     ! ~9 n% \8 A0 M% l& N) V
  11.     // 关闭错误报告( o& u( {3 ?, d# f1 V9 J9 @  }
  12.      error_reporting(0);
    + T6 r8 e" b5 l, D
  13.   z4 A* \5 }3 M9 o$ |: {4 z
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* N+ H. A+ k% o
  15.     $dbuser = 'root';            // mysql用户名. \8 i$ }0 u- G3 V, F% X
  16.     $dbpass = 'root';          // mysql用户名密码
    7 @. E" Z7 o6 ?4 z: ~! C; `2 ?# f
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    . R# u: y& V8 F+ a. n& f
  18.     if(! $conn )0 R- T3 ~! D1 e# f
  19.     {
    & C" ]6 P. v) J, k6 [; y
  20.         die('连接失败: ' . mysqli_error($conn));
    " v3 H& ^0 r8 v$ m5 Q
  21.     }- K+ ~6 ^; S3 U# R; f$ A
  22.     // 设置编码,防止中文乱码+ E8 e0 Y1 S3 E, C6 D( c
  23.     mysqli_query($conn , "set names utf8");
    1 C# [8 J( ~$ V: r" b9 u9 M. i
  24.     mysqli_select_db( $conn, 'temp' ); & f3 k6 o% V& Z5 w3 B; l4 [1 R( f
  25. # h- Y. \0 T# X5 P/ Y6 U. Z
  26.     # mysql 锁
    - ]# q+ N! x# S, ~# Z7 m& b
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这   F1 C+ u3 ]2 `& \0 y- k: X% _6 c3 |
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); : o0 G2 S; g. g- }! A6 t) @; l
  29.     $id = mysqli_result($rs, 0, 0); . {/ {* j1 H) n! ]" I9 J7 i
  30.     if($id > 0) 2 P9 m- M. y. w( Z
  31.     { + y8 q# Q  a4 F7 X1 ~3 X
  32.         --$id;
    4 I, a' D, Q$ O
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 6 f, c. ~' G' d3 P$ \
  34.     } ' o! |, }% m  ?; s/ l% I7 x7 J% S
  35. ' `! o! j$ B: N9 g
  36.     # mysql 解锁
    / u! t1 n+ J6 h+ A0 O) g
  37.     mysqli_query($conn , 'UNLOCK TABLES');  K8 O# y7 e2 r0 `
  38.     //查询解锁后的id值
    5 ^, Z" J1 v8 ?  O
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');4 A1 @# |; `7 g9 {" H; k- `+ j
  40.     // while($row = mysqli_fetch_assoc($res))- |% o. U* g7 M( l. v
  41.     // {
    * ]0 U% ^& q# R
  42.     //     $id = $row['id'];
    9 C( r+ Q3 m1 c4 h5 H$ S
  43.     // }+ s" W2 ^( J6 t1 x) E4 a( z
  44.     // echo $id;
复制代码
) W% u9 m# g/ I
" y6 `; c( S, M! R5 r" C$ k

3 t5 C0 P6 u5 l
PHP文件锁示例:
  1. /*! m3 r/ @: j7 k
  2.     模拟秒杀活动-- 商品100件
    - R9 f& a: T& N( R: K9 e
  3.     CREATE TABLE ta+ }. y5 F" w- Z) s8 q, h: Z7 d) e
  4.     (
    & I) e' _8 K) @9 Z( I; T
  5.         id int comment '模拟100件活动商品的数量'% F5 J5 O( j& O8 {3 _
  6.     );
    ; O+ M/ S$ f+ `8 ]: |
  7.     INSERT INTO ta VALUES(100);
    ( o4 I1 w! k. M) m" {$ X
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件4 T- \$ ^3 i) S3 Q$ t
  9.      */ + D1 U6 Z6 v% N1 z! m3 W
  10.    
    ) q2 Z- K; S% L* @& b& i
  11.     // 关闭错误报告
      A* R9 T& e8 d8 O; g
  12.      error_reporting(0);
    0 d9 V9 V* t  j

  13. + x/ b7 y7 }1 u) a* H" ?
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    / e; ^$ H$ `6 ?% y% \8 b1 U4 |' L
  15.     $dbuser = 'root';            // mysql用户名
    ( e) L8 @% {5 p
  16.     $dbpass = 'root';          // mysql用户名密码9 T+ T1 v$ T: Q
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    8 v7 D/ N1 s0 f7 x
  18.     if(! $conn )
    + o4 p4 ^1 L" x2 o% s4 h+ C
  19.     {6 _+ g0 J9 O+ D- B7 J
  20.         die('连接失败: ' . mysqli_error($conn));
    : m7 Y7 T8 h2 O3 V/ L6 n
  21.     }2 q# Z# y4 m9 k0 M: L( r
  22.     // 设置编码,防止中文乱码, P# `' l1 e+ ~# u" u) ]
  23.     mysqli_query($conn , "set names utf8");; f% x# C" o! r9 W4 h, g, X$ f
  24.     mysqli_select_db( $conn, 'temp' );
    7 c+ s# h( Q- U
  25. 0 {5 W, `* [! i' T1 U
  26.     # php中的文件锁 ' z2 O+ ]; _9 U$ G
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 7 D* |  J! C2 J: _6 s( ~( i7 B1 Y
  28.     flock($fp, LOCK_EX);// 排他锁 + _/ f7 [* X9 w
  29. 2 O* e) S0 X1 D0 Y6 |
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); : g1 b3 ]3 m! Y8 m7 n) C
  31.     while($row = mysqli_fetch_assoc($retval))
    0 r& v, ^( N3 ?% L
  32.     {
    ! t: n3 \. [) e# J+ b
  33.         $id =  $row['id'];
    6 j6 `5 ~# e6 a" K, d: c7 V
  34.     }
    6 `9 G3 f& b' b
  35.     ( C' o3 P) ]  e) t* Q( @2 }% i
  36.     if($id > 0)
    " L* ?  G9 X8 P7 g# g( d
  37.     { 9 s, N( T% M7 A2 U$ ~8 `) w
  38.         --$id;
    4 J9 U4 ?3 k  X- k3 f
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    ! \3 `: |# @" y
  40.     }
    8 o4 w) e9 O& v* U  z
  41.     # php的文件锁,释放锁 $ y) k, ^: w. h6 ?
  42.     flock($fp, LOCK_UN); - Q7 ]" W; a8 Q% x/ A1 S$ q2 o! X, ?, s
  43.     fclose($fp);5 y8 i" x  V8 U% Y
  44. ( n, F/ Q, U* @  ?
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');! j: \+ g. \+ i1 d& \7 ~8 A0 C
  46.     // while($row = mysqli_fetch_assoc($res))
    ! W! x7 r, R3 \% O
  47.     // {, l1 I$ K) m1 ^0 l: N# w
  48.     //     $id = $row['id'];) j" s  z2 U7 e0 {0 }/ n, J
  49.     // }
    . O+ T& }( R7 C% [. \5 }
  50.     // echo $id;
复制代码
, @) n3 q+ I+ V/ P  X1 q$ _' J
& X  M5 p3 e4 a1 c- K: H2 U7 H
抢券活动实例:
  1. public function envelopeSnatching(){
    , L8 Y2 y' G3 S$ R, T
  2.         $lingqu = $_POST['type'];
    - a: Y$ f. G9 p: w
  3.         $uid=session('u_id');//用户id0 `+ ^8 C9 v, T9 g; }" l
  4.         if(!$uid){
    % i# T7 t, @& }8 z
  5.             $data['msg']='您没登录,请先登录!';
      |$ d  c, n0 M6 T0 u- O8 I
  6.         }else if(date('Y-m-d') != '2017-12-12'){( P, J6 M0 W0 |6 P" u7 _
  7.             $data['msg']='不在活动时间内!';
    ; |. u% R7 \% l; B2 x
  8.         }else{
    / t5 y6 W+ ?$ N3 V7 C
  9.             $hours=date('H');//当前小时数4 [$ s# E) c/ D  j5 j0 w
  10.             if($hours > '09' || $hours > '17'){) h. @2 F$ j, ]1 u6 ~9 \8 B
  11. 5 z4 Z$ c- \, L3 f9 e3 K, w
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    % x: G- g- ^2 o: u
  13.                     if($lingqu == 1){
    : f7 [6 v7 X# o/ G
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    * X$ m! i1 g; j! d
  15.                         if($hours > '09'){
    4 d' @" C7 L* |
  16.                             $num=mt_rand(25,28);//优惠券金额: V; j& x9 E" z* o) I6 y3 p6 M
  17.                             $id=1;% O" v/ B5 l5 d: r4 Z! Q
  18.                         }
      V- ^* m3 H5 r, C: V* j! F! l! k( a
  19.                     }else if($lingqu == 2){
    . u/ E7 a4 H9 `9 X
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    $ J  L, E: v( i1 A
  21.                         if($hours > '17'){
    5 ]; K0 Q7 F% D% s- i: E
  22.                             $num=mt_rand(50,55);//优惠券金额
    . s; q+ N' q1 ]
  23.                             $id=2;
    6 f& b; Q( r* ^
  24.                         }
    0 |. p( W8 Q, b( R
  25.                     }
      @1 g! I; l- x8 G' F
  26.                     if(!$id){/ Q$ X$ c; E" x* t
  27.                         $data['msg']='时间还没到,晚点再来吧。';" o% A5 Z4 O2 x; M0 ]9 c, b* l
  28.                     }else{
    / @) D; n1 T8 [3 D6 ^4 ?
  29.                         if($is_lingqu){
    ) r1 r+ E1 u" h7 c3 ]
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    ( ~* l% F* r: T2 b9 l. q
  31.                         }else{
    2 _5 I5 T& K* }5 C0 l! Q; y" X
  32.                             //锁表
    / s9 w2 f2 J, Y" u: _+ v# G$ h
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
      T6 A" }1 Y7 M  x, B8 G3 X9 [
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();; B6 R+ H0 G. l+ i% Z
  35.                             if($active > 0){' z; Z) Y2 j  @9 E. t0 |' x
  36.                                 //开启事务5 G  X2 i  ]  ]
  37.                                 M()->execute('start transaction');$ I" d  Y% r6 P/ P. s- \# b7 R$ T2 C
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    5 u* L! }- f# I, s; I
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    5 X* W4 K0 D7 h  [7 _6 t8 T
  40.                                 $members_preferential    =    M('members_preferential');
    9 u8 k. q/ S4 x) j, W
  41.                                 //对应投资金额,
    - c: |7 |8 A  N$ f  h; f1 e
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    1 L- @& r' m1 X( L$ c! I
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');0 ]: v% Y# w) a$ w
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间- T+ F0 q& Y5 o
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券1 n( J9 K0 }! }3 M
  46.                                 if($save && $add && $add2){1 K! ~. w# Q9 W' L5 S: J- R1 {) o3 D
  47.                                     //事务提交
    9 l$ e  s+ D/ V
  48.                                     M()->execute('commit');+ q# N: {( {0 g3 o2 W; n
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';& g7 D4 W& e8 F7 Q1 }
  50.                                 }else{
    3 G0 o3 {; T1 P4 B
  51.                                     //回滚$ F% j9 c+ Z* {
  52.                                     M()->execute('rollback');
    8 M1 q5 L/ G9 `2 x7 T3 S
  53.                                     $data['msg']='未知错误!';
    9 r3 W2 i) H, Y8 O+ o% r
  54.                                 }
    8 X# `  F# q( b! ~
  55.                             }else{
    4 D! h" O( b: n# g
  56.                                 $data['msg']='红包已领完,你来晚了!';6 a3 M, T- h" J" u
  57.                             }
    5 [7 t) Q! E1 G/ X* ^6 f/ v
  58.                             M()->execute('UNLOCK TABLES');; U/ }  w4 N, ]  J
  59.                         }6 L; m9 S  g+ m* O% f9 R
  60.                     }+ j4 e* |# r! X2 v
  61.                 }else{
    % D2 y& J* E0 O
  62.                     $data['msg']='非法操作!';5 T0 g! y/ K( F* L! a
  63.                 }8 n* K6 q( p$ F' d4 ]; L
  64.             }else{2 o2 a. p' Y5 Y8 v( M6 ?
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    8 [& u$ a- d: V  X
  66.             }
    # Q6 u$ O6 }7 i3 R
  67.         }0 b, h# ]/ @5 C# t$ {+ i
  68.         exit(json_encode($data));# [# M/ a) E2 ^& L# ^1 `
  69.     }
复制代码

: ~  R/ J2 s% [5 ]
' @" Q, M' w% c6 C) e9 U: ~4 V* B. s




欢迎光临 cncml手绘网 (http://bbs.cncml.com/) Powered by Discuz! X3.2