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://请求的脚本
复制代码
% [- B. L% V8 L( B6 d& S3 ?
Mysql中的锁语法:
$ U4 k' S# J/ A$ s' w4 y" m# c0 H4 |LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】6 `6 ^: O' b/ M; M
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
9 L/ C- G: b2 U6 x$ @6 ?8 hWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
) y+ L1 G  E& l3 j3 m注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
" r' M% ?' Y3 I! Z0 u4 x文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。2 c  `$ [% `8 k4 F% _, l
测试时,有个文件就行,叫什么名无所谓
总结:, O) j! T% t! N' I( R3 M4 B
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:; P& A3 k6 i$ q: L4 Q4 C4 ~: F
1. 高并发下单时,减库存量时要加锁! ?6 d" e7 s6 J* P0 I) }0 q
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*6 j3 j. P, C) O6 {7 ^5 I+ n4 Y7 x
  2.     模拟秒杀活动-- 商品100件: R) C; n7 i& I6 Q2 m  ]5 B
  3.     CREATE TABLE ta
    ' {6 X( L5 V: e! R- ?( ]4 v
  4.     (
    5 `$ s% Y0 X2 Y6 C! c  S
  5.         id int comment '模拟100件活动商品的数量'
    ( B2 I4 A) d* t: n& t* x
  6.     );
    : _- J/ a/ R* e6 P
  7.     INSERT INTO ta VALUES(100);; P4 P8 l. P  D
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ; q3 a( l. T9 V- y9 X* m
  9.      */
    , |5 n4 @: k8 N4 |! w- \
  10.    
    3 z0 H6 J) j8 @3 A/ G
  11.     // 关闭错误报告& a/ Z5 e# Z) \. `
  12.      error_reporting(0);
    6 p* Z: F0 o; c" T6 b; ]

  13. 6 Q( T% l9 Q# A# @
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    / u: v3 e3 o3 k; V
  15.     $dbuser = 'root';            // mysql用户名
      ?/ b9 ?% \, ^3 L" K% X$ O
  16.     $dbpass = 'root';          // mysql用户名密码1 W: t$ u/ @0 X) _6 d; L: N
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);) J& Y& E$ b& g5 q$ W0 r
  18.     if(! $conn )1 F. C1 y! y6 J* {/ D" T
  19.     {
    7 F/ z% L' s, ^3 @* z4 p
  20.         die('连接失败: ' . mysqli_error($conn));
    4 H5 h! [: x  j. i" x& w. X
  21.     }- J- a: [8 C( [) f# g8 m
  22.     // 设置编码,防止中文乱码
    # {9 t/ w; H& c6 m# l; B
  23.     mysqli_query($conn , "set names utf8");
    9 g$ P; n& n0 h1 }! Q
  24.     mysqli_select_db( $conn, 'temp' );
    # q+ {& R$ p( l& }8 u  s8 ?3 |8 [
  25. 5 X) F$ L' Z7 z- C8 H9 i) {; J
  26.     # mysql 锁 0 |0 l' G. y( K& w2 D/ Q! P
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    8 ]* Y0 I( P0 f/ ~3 M$ c) k9 j9 M& z
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 1 @/ K5 `- k+ \% I* c
  29.     $id = mysqli_result($rs, 0, 0);
    0 K$ z9 d: s4 E1 `* \
  30.     if($id > 0)
    6 F& j1 ]6 l& {2 e- K0 m- y1 C
  31.     {
    5 ^0 A, U* ^: k
  32.         --$id; ; j4 J/ X1 t! b: Z0 Y  d7 N7 c
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    / P3 @% _8 ]4 m% c5 j9 O
  34.     }
    0 c4 _2 k- P3 X: r, I, s

  35. 1 @0 {! n5 k3 ^
  36.     # mysql 解锁
    ) P6 ?# C8 m+ \/ z! q
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ! f6 x( f2 i& @2 {- Z7 A) c
  38.     //查询解锁后的id值
    7 J% _, D& n  N8 y4 I0 T
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    2 T5 P. M+ F6 A6 Q* s4 t
  40.     // while($row = mysqli_fetch_assoc($res))
    ; J  q! N7 v6 B2 F! L* q/ H
  41.     // {/ P9 G( A* F5 X
  42.     //     $id = $row['id'];
    0 c+ p7 P% Q* {2 |5 p( t
  43.     // }
    ! r, a3 ?9 [. ]( |, O# T% K
  44.     // echo $id;
复制代码
2 e4 |. S" E4 _& R2 X! ^7 ]

" b2 Q; ~8 h: Y, v" m- Z+ H; h
5 P* i7 @* G4 W9 y+ A1 C
PHP文件锁示例:
  1. /*4 n3 L$ ?7 y* Q$ t9 P, q% ?& ^
  2.     模拟秒杀活动-- 商品100件. o0 _6 _8 I9 {1 Q' B
  3.     CREATE TABLE ta0 h! F5 ]3 G, ]) s9 b6 t
  4.     (4 H% h5 t. v% n+ k0 i) k
  5.         id int comment '模拟100件活动商品的数量'
      h: j0 C* O* A
  6.     );
    8 F$ u; N* K, O* Q0 k, m
  7.     INSERT INTO ta VALUES(100);4 r; ~8 _+ D7 p
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件7 {4 q' I, c. t1 k! D
  9.      */
    6 i1 V% ?' M8 X% U
  10.    
    ; ^/ ]) Z: n5 s* ~2 m
  11.     // 关闭错误报告
    + {: x+ U( Q" f: D
  12.      error_reporting(0);
    0 o% A" |+ ]8 J6 T; @* o
  13. ! g9 |1 X" P% Y! N8 Z* y: r, a
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    7 X- x& r' U, `& j5 n
  15.     $dbuser = 'root';            // mysql用户名
    3 S% \. D$ s6 k' B+ @' U
  16.     $dbpass = 'root';          // mysql用户名密码
    8 R  S9 g, {" d
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);9 B  {' o5 D9 b, L5 R7 {7 v
  18.     if(! $conn )+ Q3 e( {- H; g6 E- |0 \) n( g7 h
  19.     {
    # X$ Y8 e' R- M. V/ k
  20.         die('连接失败: ' . mysqli_error($conn));
    + N: S9 m8 w' Z8 R3 K
  21.     }
    ' |! a9 ]% z, e/ b
  22.     // 设置编码,防止中文乱码% f- J0 M; ]& e2 n! |- ^! d
  23.     mysqli_query($conn , "set names utf8");
    4 O$ u& K- v3 P! r1 s
  24.     mysqli_select_db( $conn, 'temp' ); ( c( C& I- I, U% z6 i+ L6 \

  25. " P! x0 u" A3 f7 d9 a; G
  26.     # php中的文件锁 8 u+ e+ B. W. T$ J
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    . w* k% m( F) t* b
  28.     flock($fp, LOCK_EX);// 排他锁
    # M  A7 Z2 F# d1 k* |

  29. 2 L; S& x5 i  T- u# Y  n. [
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    : A9 t* F! z' x7 I$ m" G8 {
  31.     while($row = mysqli_fetch_assoc($retval))' }4 g* ?/ \, q' b2 U$ n
  32.     {
    + z1 V. ?" l7 s5 d8 j, f' E
  33.         $id =  $row['id'];7 ^2 ^( U, Z, U0 Y2 Y! _' R" B
  34.     }
    & o" v& g5 d% ]  J" t8 L1 @
  35.     6 t9 t- K4 y% ~' y$ j7 [; d
  36.     if($id > 0) ' N! y/ m, i6 O8 B
  37.     {
    / [! G, [# Y0 v" S' C& O
  38.         --$id; + R( ?: n# ?+ ~$ ~9 f- X7 D
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    % W" X* N' Y- o, e, }
  40.     }   z' ?1 X/ u$ v, p6 j5 _0 h3 p
  41.     # php的文件锁,释放锁
    . ?  Q; |& x# n  q
  42.     flock($fp, LOCK_UN);
    - j* U6 R6 C9 a5 ]
  43.     fclose($fp);
    # }1 |, @8 k9 s# r
  44. 2 U( K* U$ @5 g8 T8 d; {4 i0 L
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');! c4 m  ]! n3 S! _6 s  ~; N: v' t
  46.     // while($row = mysqli_fetch_assoc($res))  W; Q" `. [& e( V  \
  47.     // {- f4 e: d5 x# W  w! l
  48.     //     $id = $row['id'];/ p+ h0 N1 h5 _& h  w
  49.     // }
    0 Z: h( u9 Y& D1 D2 B
  50.     // echo $id;
复制代码
' ~& }4 k: F) E0 A: ~9 ~4 w1 t
" e; v9 l: w: U5 N% |
抢券活动实例:
  1. public function envelopeSnatching(){
    2 G2 j. V, u' z. W
  2.         $lingqu = $_POST['type'];
    7 o2 I* y$ J: g0 [/ A
  3.         $uid=session('u_id');//用户id
    & R/ k2 D0 u3 ], u7 {; F- C! s. k+ u
  4.         if(!$uid){
    / s+ r$ x8 a1 }" n# i
  5.             $data['msg']='您没登录,请先登录!';
    # N% B9 d4 V. Q" Q/ w# r. m: ?% S
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    % c  v& {% i) F
  7.             $data['msg']='不在活动时间内!';* N8 j0 ]& x. n0 @3 v- b$ H' u
  8.         }else{
    - X5 t8 e1 W1 [8 w% i! |- M% }. e9 _
  9.             $hours=date('H');//当前小时数3 M+ O4 O* M0 j+ A
  10.             if($hours > '09' || $hours > '17'){
    9 m% S# s5 j" [, i" y! S' m
  11. ! U! A" G4 t7 m- |" t
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    $ j" [/ b" n9 p! e- C! B
  13.                     if($lingqu == 1){( H- \7 d! R, r
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    * K- K2 X5 L* F6 V0 \( H
  15.                         if($hours > '09'){0 @5 C0 I6 |9 y+ v: B' O
  16.                             $num=mt_rand(25,28);//优惠券金额0 G$ |- l5 n7 L0 I3 ~
  17.                             $id=1;6 @" c0 n" m/ y/ S1 E2 C9 Y
  18.                         }5 J( s$ P9 |# S* k
  19.                     }else if($lingqu == 2){
    ; I. N% O" f4 Q: y/ H' Y
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();# }  [; u% o' Y. h8 o  u
  21.                         if($hours > '17'){
    8 R3 x# s8 x( q# b1 U
  22.                             $num=mt_rand(50,55);//优惠券金额$ P( K  w9 o7 T! ?" B
  23.                             $id=2;2 t2 A! h7 H8 h  U* a$ i
  24.                         }9 t: Z- V) h; d! S# m1 }
  25.                     }
    % x' d9 e$ \2 P0 G$ a# Z) m1 H6 E
  26.                     if(!$id){
    * }6 ~) Q1 y5 ^1 u$ V9 |- Y. a
  27.                         $data['msg']='时间还没到,晚点再来吧。';' r7 l& }9 r1 ^5 Y
  28.                     }else{3 D* M2 x8 l1 k) N. ?
  29.                         if($is_lingqu){. y6 O) A7 k! \4 l3 ?
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    ; o- r  [& b+ K# ]1 q
  31.                         }else{
    + H6 o5 s) A( K+ O' d* N# T2 _
  32.                             //锁表7 n0 [- E( T8 ~' @/ S$ x
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');$ V7 e  S5 |6 X2 k1 }# O
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    & k/ u; I! g; w/ V- y
  35.                             if($active > 0){# i0 R0 Z1 M3 \) {" s- X
  36.                                 //开启事务
    2 h' g/ Z+ q& ?
  37.                                 M()->execute('start transaction');0 _" a( N* \2 \. N" Z
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));/ |) Y6 Z# r4 G% \* G" q8 N
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    - i5 `; k$ a' b6 ~% F
  40.                                 $members_preferential    =    M('members_preferential');
    : v+ D7 i( P5 c5 u
  41.                                 //对应投资金额,( j% u( q% ]) h1 b
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    6 u9 E6 L- F+ L1 t  v* D
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    , R" q' Q4 M' e, A2 Y+ ?
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    / {; s9 i7 l3 [* u& V5 I% ]
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券" s) Q! _  ]# h. O0 G7 _5 A7 L
  46.                                 if($save && $add && $add2){4 u" W: e/ m4 Q  Z
  47.                                     //事务提交
    8 F3 p# _8 R) _$ |8 p& N
  48.                                     M()->execute('commit');
    / |, i# h! L0 b- |
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';# S9 [8 L8 \  `8 q8 K7 e
  50.                                 }else{
    " b2 y  S" r% O- A$ a
  51.                                     //回滚) D- P( P1 U& e
  52.                                     M()->execute('rollback');
    ; L$ g% J6 M' ^0 a5 d! {, c
  53.                                     $data['msg']='未知错误!';0 R$ q! l. ^( U) }+ k
  54.                                 }
    7 x2 \4 a9 L/ s1 m6 |; z% u
  55.                             }else{8 T: i$ v) L% B1 j3 Z0 V% H+ G
  56.                                 $data['msg']='红包已领完,你来晚了!';% l9 M, Q. M6 X5 [4 `1 U
  57.                             }+ L9 ^' R8 M* z* E
  58.                             M()->execute('UNLOCK TABLES');  }( q/ X/ k/ E. A
  59.                         }
    ; k2 H' [( z2 a
  60.                     }
    9 O. t; a5 g& e5 i
  61.                 }else{
    ( B1 `: m7 [5 |$ l$ D0 w
  62.                     $data['msg']='非法操作!';# I) t$ P4 d0 N9 @9 r
  63.                 }( z5 C$ e: @0 Z4 g
  64.             }else{
    ' p, C0 [, a3 ?" D( G  Q
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';9 |) W: b( Q5 e# C
  66.             }
    " Z7 L: O+ l' T+ ~2 ?
  67.         }- E1 b4 \4 r9 y$ ]" E2 T- Y7 m0 U  N
  68.         exit(json_encode($data));' E0 f2 c/ {( c* [7 o' q
  69.     }
复制代码

2 s! x+ ?- z! {" p3 U" l) ~7 x7 X" I
: I3 J  X$ G& |# i9 l! {  o; w




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