您尚未登录,请登录后浏览更多内容! 登录 | 立即注册

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8363|回复: 0
打印 上一主题 下一主题

[php学习资料] MySQL(表锁)、PHP(文件锁)锁机制及应用场景

[复制链接]
跳转到指定楼层
楼主
发表于 2022-3-17 15:53:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量
  1. C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php   // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
) A# `+ l( ^* K$ E( n2 F
Mysql中的锁语法:( j( U# @6 Y  P! E' }6 `
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
1 ]1 L! p9 E3 ]# z  {9 P) T, iUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
4 b% n! P) c- N0 p* t* w, B" sWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
$ b) M6 I$ u+ J: Q/ _9 @4 c注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :) W3 a5 f% w4 W8 k
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。, A- Y4 O% G. L6 S+ t
测试时,有个文件就行,叫什么名无所谓
总结:
0 E4 y. k, L/ y/ E项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:! c4 K+ X: E) c/ ?! t7 q, j* H
1. 高并发下单时,减库存量时要加锁
, R! [$ q- v3 b  `8 ?2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*, X5 t# j: R! s- D; |# j/ M! x
  2.     模拟秒杀活动-- 商品100件
    & C- ]7 y( y; a4 u
  3.     CREATE TABLE ta
    * l, F5 S1 y6 b% ~# l$ g! e
  4.     (
    9 T7 x: {5 B, w# ]! i) e( o! m5 Q
  5.         id int comment '模拟100件活动商品的数量'6 X& f* n8 M* Q% g0 w" ^
  6.     );
    / x! A8 B& S. E/ P; Y- s: x! c2 h
  7.     INSERT INTO ta VALUES(100);
    ) b& W9 N5 d. f; o- b
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件9 Y- J1 t7 m7 C* x
  9.      */
    , k& x  ?* q0 b8 p4 _" h
  10.     ) M+ r! A4 I' }) E1 N5 Z( s
  11.     // 关闭错误报告
    0 P3 }" x- e5 B2 s
  12.      error_reporting(0);
    & W# h; g  @$ c$ M: ?

  13. : Z7 `1 e2 c) O/ q. M+ z, J3 e
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址. W2 P) o: }% \% }4 @3 l( e
  15.     $dbuser = 'root';            // mysql用户名& n% d2 R0 V) L, ]) D. H
  16.     $dbpass = 'root';          // mysql用户名密码5 c) s2 P* c8 j$ c! o
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ) b# j. B9 z. x; `5 l9 [* C1 t
  18.     if(! $conn ): Y1 A! m+ y4 ]+ e$ W
  19.     {
    # F8 J0 u4 A7 z- @% J( m
  20.         die('连接失败: ' . mysqli_error($conn));& R$ O0 v$ R' A6 M+ z) b- C
  21.     }
    . i) O6 b/ {% x" ~( F' c! q8 k* N
  22.     // 设置编码,防止中文乱码
    ; U& F+ [& W1 d& r# h
  23.     mysqli_query($conn , "set names utf8");1 W( O0 x" R2 f  o
  24.     mysqli_select_db( $conn, 'temp' ); , y; r: x+ _( p5 C9 K& h! i

  25. 4 k" R+ U" y* W) q2 E# X# }
  26.     # mysql 锁
    7 x6 A0 _% n! G2 I: ?. o; Q" w* h/ @
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这   q3 J: E) U* @% k& M$ q
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); & O$ b! J( M  g. Z9 u" ~4 g, F& `
  29.     $id = mysqli_result($rs, 0, 0); $ o  M% d1 n5 e9 @% |
  30.     if($id > 0) 4 u2 M3 _7 m8 k4 }9 `
  31.     {
    " e6 a& b2 @* R" e! t
  32.         --$id;
    ( R2 X0 p( n& k+ S
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 3 {4 _8 h! v; Z% s( B
  34.     }
    . u/ I( @, I  [# i& {# P. @- [
  35.   C) Y- s: s3 ~2 e4 l
  36.     # mysql 解锁
    ( p' k' H1 I) ^/ U& a7 E, F3 X& @% Q
  37.     mysqli_query($conn , 'UNLOCK TABLES');8 t/ C6 ]+ w& \+ `) H  P' E
  38.     //查询解锁后的id值1 `3 o% H9 f9 {4 w
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');5 _4 y, {" ~* p, [' i- A
  40.     // while($row = mysqli_fetch_assoc($res))4 Q' u4 f  O. t- s( p/ h
  41.     // {
    , f! T1 y  r- k* M9 v; N9 k$ F
  42.     //     $id = $row['id'];8 K) |% ~5 M2 s& d
  43.     // }
    9 G0 c1 ?+ k8 `! C  x% m
  44.     // echo $id;
复制代码

, m4 L# q: k. I& v( k! A* N+ ]
. v; r- n/ o  v5 I3 p
5 c5 z. @$ h; G" M
PHP文件锁示例:
  1. /*; J3 U4 ]1 [. m6 a/ N
  2.     模拟秒杀活动-- 商品100件/ W) X2 S' ~  o5 G- K# b) d
  3.     CREATE TABLE ta+ h3 C4 r/ }2 V0 Y+ _+ Q
  4.     ($ V! r! J! ~7 k7 d4 t& R
  5.         id int comment '模拟100件活动商品的数量'3 E" m$ y! F# J2 m
  6.     );
    7 x8 c: Y0 z: c, ~
  7.     INSERT INTO ta VALUES(100);
    ) O: n6 G; }$ \8 K. t8 }% l
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件: P3 G: O! V5 a6 p1 l
  9.      */
    7 T: b3 L: n3 U& Q3 q3 ~, ?
  10.     ( M9 y  {# W0 e9 i& K
  11.     // 关闭错误报告/ |. O% |8 q2 V& H" j6 m' K/ X
  12.      error_reporting(0); 4 y# t0 F; |3 O! l0 A
  13. 6 W" U6 k, q) D* m
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址, k  J: N  Y3 u6 R5 r* A
  15.     $dbuser = 'root';            // mysql用户名1 H- v. W) ?4 s8 U
  16.     $dbpass = 'root';          // mysql用户名密码. v/ o8 b4 U( m/ x
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);4 s9 `3 T* }% J, T" C
  18.     if(! $conn )
    1 r7 B& F4 ~9 @, F
  19.     {
    1 [! S) A: n9 @7 [% h7 w
  20.         die('连接失败: ' . mysqli_error($conn));
    & D0 Q; s9 p( \. U6 E4 _+ a2 H
  21.     }
    * h/ b9 H. t0 q+ [
  22.     // 设置编码,防止中文乱码. D9 K2 c' o; ~: x5 u) r
  23.     mysqli_query($conn , "set names utf8");6 q. r5 D4 H7 H" Y* Q2 F
  24.     mysqli_select_db( $conn, 'temp' ); : ~# [. S. Q- O4 C2 p5 X

  25. ; j% H  f: E) {! Y, i+ M: n% u
  26.     # php中的文件锁
    , s: J8 w' ~1 T1 o8 o0 s
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    ) ?+ u1 N0 F2 ~1 `
  28.     flock($fp, LOCK_EX);// 排他锁 9 ^4 d6 @# ~1 ^* {  U2 v
  29. ) U% S$ @, h% |& Q# v* r
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
      W3 V2 @, k* b& l
  31.     while($row = mysqli_fetch_assoc($retval))- q" V' w9 P* D2 ^" O& H
  32.     {
    ) r3 W) _: u( O# F+ p
  33.         $id =  $row['id'];' m' |+ M" J& V( G9 Y! {+ A! ~
  34.     }
    4 k0 e/ K1 K& _+ l( r
  35.    
    % \; R1 {: |3 G; z2 t9 E% S2 s+ Y
  36.     if($id > 0) ; c) p; M' q/ I! O
  37.     { $ Y& r2 u$ C7 M9 h! ]! w
  38.         --$id; * I# Y/ K1 O" A  M/ H3 c! U
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); / D! q7 l* X# y7 \) n
  40.     }
    , e5 [$ M( q; v
  41.     # php的文件锁,释放锁 $ _  b0 q/ q+ S. g( x
  42.     flock($fp, LOCK_UN);
    $ }; ]: m8 w' o2 k
  43.     fclose($fp);- B* [1 b; C7 L$ ]0 T! W
  44. 4 J* l$ O( w* ]6 I2 \
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');0 g, E0 }  A; d+ J, B3 |
  46.     // while($row = mysqli_fetch_assoc($res))# ^2 Y, R" h5 ?7 J
  47.     // {
    6 x6 S- s7 F7 n: d
  48.     //     $id = $row['id'];6 G( O5 u  @$ M6 F- a9 O2 d/ n+ L! c; _
  49.     // }, A; t$ Y4 r) m5 Q  b
  50.     // echo $id;
复制代码
& m7 Z. {) `- o; d. j3 R8 f* f, a
+ O2 [3 `6 ]5 E1 r4 A$ o
抢券活动实例:
  1. public function envelopeSnatching(){: R! z: H  Y; v5 O- ^( O
  2.         $lingqu = $_POST['type'];
    ! J# d3 E2 o$ k! ]& l
  3.         $uid=session('u_id');//用户id  D' Y, R& i4 y8 I  X
  4.         if(!$uid){; z' k0 {; Z& ]9 O
  5.             $data['msg']='您没登录,请先登录!';$ C( c0 T( e8 w4 Z" X+ F+ o7 F
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    ; W2 ^6 k" Q: p& e% ?& B8 r
  7.             $data['msg']='不在活动时间内!';
    . x; h- b! y$ g8 j5 k; C
  8.         }else{
    0 z9 j/ S7 b7 B9 U9 Q5 t5 ~
  9.             $hours=date('H');//当前小时数
    : ?% \- R. F* V+ d
  10.             if($hours > '09' || $hours > '17'){
    ' i5 p  w( i2 [7 j% v2 r
  11. 7 j0 o' g; c4 \+ X9 J
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    9 v# B2 {( z+ P
  13.                     if($lingqu == 1){; F! c& ]0 X$ `# i
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    + _2 s" Y5 r. {2 C- J/ E
  15.                         if($hours > '09'){3 G7 p8 \6 c' B; S' H: T
  16.                             $num=mt_rand(25,28);//优惠券金额/ X/ x/ [1 G* E
  17.                             $id=1;
    5 g0 T& O; C" _, a4 Q2 v9 ]
  18.                         }/ {% S' a. u/ u! {4 E/ o7 ^
  19.                     }else if($lingqu == 2){
    0 E* o6 y- f/ w" ]
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();+ l* S$ v. O" S: R2 J7 O+ z5 {
  21.                         if($hours > '17'){3 g4 F& Z: M% ]5 T* A
  22.                             $num=mt_rand(50,55);//优惠券金额' \" d/ e- V7 \! v1 m$ k
  23.                             $id=2;
    . e& w3 v9 M, e2 p
  24.                         }( p( i" a( O% o
  25.                     }
    6 @+ c4 w% p3 e* n  m& c: k, T% V
  26.                     if(!$id){
    ' ~1 h2 @$ }# }+ q5 M# Q7 }+ N1 R
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    1 K+ E5 ?: M, Y0 A& d. W
  28.                     }else{
    3 r, m# V* V3 N3 K& _$ S2 d
  29.                         if($is_lingqu){
    1 u1 h3 X( v% t2 b
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    0 I& ?  L  S0 v# o6 z  ?
  31.                         }else{
    3 O- {8 c' g+ a
  32.                             //锁表" N- X; J" u( w) n& k
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    5 g9 t) V* J/ j
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();8 u! O$ t7 E! t  @& m$ X
  35.                             if($active > 0){
      H5 A  m: Q& h2 |0 y$ p
  36.                                 //开启事务
    ; _* D  I# M- B! y: u6 x* C0 Y; N
  37.                                 M()->execute('start transaction');
    ) H8 t. h$ N& h7 Q) Y0 k7 p6 J
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    , }, l" ]* @! d
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));8 h+ I7 U7 G7 \8 X, U
  40.                                 $members_preferential    =    M('members_preferential');
    + j  i. g5 j2 y& `
  41.                                 //对应投资金额,
    8 q* t6 ]( M; Y3 i( m
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ; m$ W. c0 F9 T; g8 X( n
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');. R5 _8 h# M2 v
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    / a4 j7 M0 W5 H# v/ Y: k% p
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券4 D/ q, n# u% m+ |3 i
  46.                                 if($save && $add && $add2){
    ( r' {* q1 @- i7 n# v) j& e2 e
  47.                                     //事务提交! H  ~+ G9 Q: w5 d% h
  48.                                     M()->execute('commit');* d; l* `, R# o6 _) W
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    6 n- a) r- l7 r( a; b% ~* ?
  50.                                 }else{+ g' q5 h3 ?, W! ?+ v# ]  S1 y
  51.                                     //回滚0 d1 B- v; {5 _- M& ~  W4 F. p" n
  52.                                     M()->execute('rollback');
    1 P' f6 j; {7 K9 m
  53.                                     $data['msg']='未知错误!';9 E( _4 R( \4 M7 H
  54.                                 }
    % |3 s5 ^0 }' H. K' z  |7 n" [6 [( \- G
  55.                             }else{
    ! G# X7 ]2 p0 t8 n0 g8 n) N' J+ _
  56.                                 $data['msg']='红包已领完,你来晚了!';/ g7 ~( w8 x* C
  57.                             }
    + F8 g1 W7 r) z; ~+ U
  58.                             M()->execute('UNLOCK TABLES');
    " `3 m/ _% d8 A1 M" b- l# P% ~- K
  59.                         }1 Y7 g) _' l1 {+ u
  60.                     }
    & i3 w" o8 s2 I9 i. u
  61.                 }else{
    0 N- \! K* t5 ?9 G8 J! c" t
  62.                     $data['msg']='非法操作!';
    8 c6 z+ V8 E' t$ U3 N  O" L
  63.                 }
    % B% ]7 Z" _( R& U
  64.             }else{
    * o, y" ]) K: M# Z
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    & Q% W0 B2 W3 z4 K8 }/ N  s
  66.             }3 @' T2 @7 _/ ]# N+ K
  67.         }: A9 b9 J/ L8 ]. Q# l
  68.         exit(json_encode($data));- C) Y' M6 `2 r3 n
  69.     }
复制代码

: h' ^9 z6 S. Y& S+ P! N7 _: c+ o2 }+ Q* Q! H
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 18:45 , Processed in 0.061474 second(s), 20 queries .

Copyright © 2001-2026 Powered by cncml! X3.2. Theme By cncml!