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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9326|回复: 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://请求的脚本
复制代码
7 |- a( e# l' s
Mysql中的锁语法:
# e1 m* a4 C9 _2 v) {* nLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】4 u* \5 n4 B9 o1 B" P7 `& A- m7 u; ?
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
' ~* c, _7 n# h& W6 r/ ~# c" N/ [Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞& x9 O' [# S) \
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :* H' s( @5 s2 O+ H
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
5 @; E! G) E  W  w- N测试时,有个文件就行,叫什么名无所谓
总结:! ~2 n* s6 s% {( Q/ ?' i
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
5 s" Z# y3 E! E! V. J# u: a1. 高并发下单时,减库存量时要加锁
- m6 t( J- y' x2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*5 b5 z2 h' _7 }3 n; B
  2.     模拟秒杀活动-- 商品100件
      [  N9 @5 b; C, @, {
  3.     CREATE TABLE ta1 }$ A0 C9 I' F& E& S
  4.     (/ ?6 p6 Z. v6 p* m& e
  5.         id int comment '模拟100件活动商品的数量'
    - d4 ^/ C6 o" `! p; I6 [
  6.     );
    $ T- V. q9 K$ Q/ C' t1 Q
  7.     INSERT INTO ta VALUES(100);
    6 h& P* C( ^' X4 h* y
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ( y2 R% X) Z( y9 ?
  9.      */ 1 b' b! J7 _: b6 C2 q5 D. H
  10.     % V! V' D# f/ x
  11.     // 关闭错误报告( U8 U6 c3 }. }6 _% x( h5 N+ {1 a
  12.      error_reporting(0);
    , J$ v7 u. K0 m: T/ W9 Z

  13. . \4 |8 T5 P& ?
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    6 T: x5 r! f3 r
  15.     $dbuser = 'root';            // mysql用户名4 W+ I* r7 P; f' F! X. b  b, V
  16.     $dbpass = 'root';          // mysql用户名密码7 T- e! S) l) X: q/ F# ?. a+ |
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    , g$ d6 R  l& ~. e
  18.     if(! $conn )
    0 R6 `4 Z- E, Q: C& C( o5 {8 P
  19.     {/ v1 c3 Z5 Z$ N
  20.         die('连接失败: ' . mysqli_error($conn));
    $ X9 u: t7 A1 ^. F+ u3 T
  21.     }
    ! V# z0 ~8 a) m, y* Q& i* U
  22.     // 设置编码,防止中文乱码8 e* O) H) p5 q, q6 T
  23.     mysqli_query($conn , "set names utf8");
    9 g) ^9 I/ N( Y: m! d) e, w
  24.     mysqli_select_db( $conn, 'temp' );
      h0 j3 z' R2 n; V4 @

  25. 2 e0 e  i) W! X& ?3 K2 J
  26.     # mysql 锁 * E# _6 t0 ?- R; L$ @0 \) R6 a! y
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    . W* n  u9 f4 `4 A* d) f  _
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); ! `# j7 E# @; h, d
  29.     $id = mysqli_result($rs, 0, 0);
    $ @2 ]% d6 T! p- ~+ k5 Y
  30.     if($id > 0)
      R; C( c1 t. X0 _
  31.     { 5 f6 Q: Y: _7 y% C) G
  32.         --$id;
    ! X8 y1 Y. O- i1 ~8 {$ ]
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    : p0 o8 k+ n5 _! |3 X) d3 J# o6 H
  34.     } 2 _2 Q* W% c' S) k. z7 Z# T0 J

  35. ) b% R1 X( Y1 A* j2 B
  36.     # mysql 解锁 : ~: k$ N+ _/ _9 f6 U' X* i
  37.     mysqli_query($conn , 'UNLOCK TABLES');4 h" l. q2 h7 v6 h5 N2 m& ]
  38.     //查询解锁后的id值
    * U( i- i5 n# _+ ]# ]4 _, y" t# E
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    : \8 ^1 ^: I/ \( d3 ~( c% ^
  40.     // while($row = mysqli_fetch_assoc($res)): _4 g+ r& F$ Y4 v
  41.     // {5 C. s4 Q9 s5 w* t4 d, \
  42.     //     $id = $row['id'];5 B1 K& `  [0 Z5 R* m
  43.     // }  K& f1 p% ]4 E9 S4 O# \# I7 n
  44.     // echo $id;
复制代码

* V" p1 b" r7 `0 N/ H& a: u
: I6 f0 D: t3 ^

( X8 C7 F7 u8 T. h# a
PHP文件锁示例:
  1. /*
    : B' q2 k+ P$ \  D! i. \; g+ q* m
  2.     模拟秒杀活动-- 商品100件9 @4 \& A1 H- a& n3 N( U# n
  3.     CREATE TABLE ta
    ; d+ G. A0 h( D  K6 X  [
  4.     (* b; ]( T0 Q" J# k
  5.         id int comment '模拟100件活动商品的数量'
    % g8 j' n+ Z6 O5 O* d  f; s( }4 M
  6.     );" ~6 w$ f2 j# M
  7.     INSERT INTO ta VALUES(100);/ j$ v. x; I* F; f/ }' N1 u  c+ N% n  |
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件* Z# `' y. Y! ]& u; R/ e& I% P
  9.      */
    4 r! y# V" [  j* f
  10.     * B7 {1 f" w: o, i: m+ ~) F' h
  11.     // 关闭错误报告7 ^6 V8 Q7 ?" N7 e9 I' Y
  12.      error_reporting(0); # n2 I3 {( T' ~6 D3 B- C+ Q
  13. # m: f% m- B+ P9 o2 s; g
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    8 E- f# y" j- }. Y3 m3 }1 ~
  15.     $dbuser = 'root';            // mysql用户名% Z% H% f. O  {7 k5 K
  16.     $dbpass = 'root';          // mysql用户名密码* Y* u2 d* C( S) o' _: A
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);! x# t3 L$ f) v; L/ o* F  [
  18.     if(! $conn )
    9 I/ u, O' i9 B1 m6 U, e
  19.     {9 [3 a2 Z+ ]; c: H8 g. t) y* j" R1 M
  20.         die('连接失败: ' . mysqli_error($conn));
    * Y, W$ x* E5 [7 h' _
  21.     }, ^+ [, E' x2 _* G, y$ e& f
  22.     // 设置编码,防止中文乱码
    5 `3 k5 E$ O" a) p" [, g
  23.     mysqli_query($conn , "set names utf8");
    1 c& {, m) ]' h& u8 r! \9 H
  24.     mysqli_select_db( $conn, 'temp' );
    2 r4 Z2 D* J. N: L7 [

  25. 1 t, Q8 e0 \) G% C3 D& @# [
  26.     # php中的文件锁 1 P9 O/ l0 I- ~  s
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 3 H5 ]  A9 R. g  _5 [
  28.     flock($fp, LOCK_EX);// 排他锁
    ; e4 U0 W$ g4 C% g7 }3 X8 d

  29. 3 c. w% z9 k( v
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    0 o* e/ o2 ~7 R( J# ^& m1 y4 b
  31.     while($row = mysqli_fetch_assoc($retval))
    : ~; U! R' E+ Q% `
  32.     {$ Q$ B8 e& K) J+ a( a5 p
  33.         $id =  $row['id'];9 [" v8 m, t: s
  34.     }
    , k( u1 I9 B/ L6 O  M7 g: O
  35.    
    0 b4 _/ J) t# Y& o# X
  36.     if($id > 0)   N, n/ j' W( R, {$ t0 l0 O
  37.     {
    ; y( \' P5 n9 p2 F, B% z" k
  38.         --$id; - G. I, z/ x. f, z- J
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); . Z* _4 {- J7 N& V& r) f5 n# t
  40.     } 8 _4 A8 M8 R; V' U! A$ g
  41.     # php的文件锁,释放锁
    1 ]/ V9 [+ E2 @0 _
  42.     flock($fp, LOCK_UN);
    ; U& G2 B1 k2 u, b6 |' v
  43.     fclose($fp);/ J0 B# Q; M" K5 o) V9 K
  44. 9 z1 j0 O* M: B, W# h
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');% Y* g6 B) \6 S$ h
  46.     // while($row = mysqli_fetch_assoc($res)); k; C+ [1 }# E/ J5 x8 Q/ W
  47.     // {
    , m' o- z. B# Q! ?1 v2 S) l1 J
  48.     //     $id = $row['id'];+ e- K4 Z6 D  T6 C+ i( g
  49.     // }' i* Q, f8 U( X0 u4 k9 x4 ^1 @
  50.     // echo $id;
复制代码
! M2 Q9 Q! @6 Q

. f6 R! A, P7 Q/ y3 C, ?+ x
抢券活动实例:
  1. public function envelopeSnatching(){
    : z: `  o2 n& V$ Q1 V4 M
  2.         $lingqu = $_POST['type'];9 ?. T/ o; Y: w% j9 @% ^
  3.         $uid=session('u_id');//用户id
    - O$ m; ~$ q. u$ P0 t
  4.         if(!$uid){
    6 ~4 ^( J$ \; J+ G; u! A
  5.             $data['msg']='您没登录,请先登录!';
    ; _/ s9 M& x4 b  C$ {
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    * n; R2 Z* P5 {2 a! d
  7.             $data['msg']='不在活动时间内!';) H( Z& X% u2 {6 D& Q
  8.         }else{9 a. P$ ?" Z' C2 h' _7 ~
  9.             $hours=date('H');//当前小时数1 O/ ]' A. G. ]5 @; n. w
  10.             if($hours > '09' || $hours > '17'){; T& o5 c, [% d

  11. & [" u3 o2 q  d9 s1 ]6 L9 H3 |" j4 s
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的. P* c  b& r0 W: a* K6 e2 }
  13.                     if($lingqu == 1){$ n, S9 E  e- h  T' u7 w
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过' U6 O% L* h, ?! t8 y6 m
  15.                         if($hours > '09'){
    8 l: V' Z( U3 `( k, S  E  z- K
  16.                             $num=mt_rand(25,28);//优惠券金额  ]2 x. I0 v5 h8 c( U. F. K* H
  17.                             $id=1;
      {8 N' ]$ |' v$ n# b) o
  18.                         }
    0 ]) Z5 r( }0 ]: ?2 \$ U" p/ W1 n! Z* ^
  19.                     }else if($lingqu == 2){% E3 [* g2 E5 }' Y4 y
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    . f1 o0 Z- m) |  g9 k$ J- C0 q
  21.                         if($hours > '17'){
    6 Z; J; r' M0 @
  22.                             $num=mt_rand(50,55);//优惠券金额
    - A, ~# R7 _3 ^/ E% M
  23.                             $id=2;
    % Q" z, t: |- e
  24.                         }
    * x8 J% `) Z; O. [9 m
  25.                     }
    ) o2 z, ], e+ @4 w- L& R
  26.                     if(!$id){$ e0 s/ n3 M7 q7 y
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    $ H+ G* v7 u8 f: O1 v/ \) @4 A  g( C
  28.                     }else{
    , e7 g) S( Y, T' d* u9 L5 D
  29.                         if($is_lingqu){
    ' i& I  G# m: o* |/ S' q5 t
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';: l$ V' [' ~+ S
  31.                         }else{4 F2 i# A7 C7 s0 A
  32.                             //锁表
    1 R/ d+ A, P: l, D
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    ( }9 r7 p7 R: q4 G4 U* q
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();  H$ N" f: w/ T7 G8 d) ^8 M9 k2 L
  35.                             if($active > 0){1 F. _7 s4 U1 v6 @5 x2 k
  36.                                 //开启事务
    " S- R9 O. J# D2 l
  37.                                 M()->execute('start transaction');
    % u# i' z/ h' R! D, T( ^
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));# A5 B& d  w% g3 R/ f  [( p# i
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));& C% K0 Q7 m8 O' v4 C* H
  40.                                 $members_preferential    =    M('members_preferential');( \: K' N& Y6 L5 M: ], d+ H7 R
  41.                                 //对应投资金额,& P9 C) ^2 O0 ~0 u: y' k/ Z$ E. t
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));, S0 ]- M7 I9 R" t5 k/ M' T
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');! Y$ t; C$ V  z% |3 c5 Y0 g5 g
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间; G+ H( N! T3 v
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    : X& g4 p% c( w
  46.                                 if($save && $add && $add2){5 S! C4 ]. Y& u6 W
  47.                                     //事务提交- I) G; i: g5 P
  48.                                     M()->execute('commit');
    1 i$ @# `3 `2 b5 @
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';8 M+ f" Q7 j+ [% V& _3 f
  50.                                 }else{& H+ R: W; `; R9 W5 ]7 P
  51.                                     //回滚
    " `" v2 h3 Y6 q6 N$ O
  52.                                     M()->execute('rollback');& T% [3 a4 d, x* y; I: e
  53.                                     $data['msg']='未知错误!';
    / c9 f- ~: C8 D( S  q9 y! n1 h: y
  54.                                 }! H/ C  i+ }4 f/ e; L! Y% M) U
  55.                             }else{
    , r; n4 O8 p: Y/ d1 d7 i
  56.                                 $data['msg']='红包已领完,你来晚了!';
    ) R; B7 q  d& s" s1 t" @; X
  57.                             }) o8 J9 w0 T, h* F( U
  58.                             M()->execute('UNLOCK TABLES');
    1 c  X! R! ^' o5 a
  59.                         }6 w( ?" J9 t/ u8 S* l
  60.                     }  i7 N( I( N9 Z" C( \
  61.                 }else{( {2 K2 V5 y% t
  62.                     $data['msg']='非法操作!';
    ! N5 D$ g. ]+ x0 _" d" H$ _
  63.                 }* h# K6 R. E9 @7 g# Q
  64.             }else{
    ; `: Z! }+ D1 t4 `/ v( e
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';" ]2 {( X. Y# T5 k& C2 ~% e) ~
  66.             }
    6 {6 l7 u# h' X8 V0 G6 U( z
  67.         }
    1 l; D/ G7 \* N
  68.         exit(json_encode($data));
    ; y7 w2 ~8 g- c  p+ l4 Y
  69.     }
复制代码
% H! }: b  }& H/ I

& W2 l4 f2 C% L$ O9 l$ Z0 I
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 07:07 , Processed in 0.061001 second(s), 19 queries .

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