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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3608|回复: 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://请求的脚本
复制代码

/ A8 @9 ^) z9 x% z8 m: E9 m
Mysql中的锁语法:: E. C, @5 {$ p0 S. t
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】+ q- U& i! H* G$ o$ |0 ]
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
1 s+ r% c8 m! g* o2 L2 rWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
3 \$ p+ n/ Q8 U3 R注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
9 L/ c2 |) ]$ n文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
9 i: P- L8 C3 \3 m0 Q* @- l测试时,有个文件就行,叫什么名无所谓
总结:3 i6 S3 P# y4 ~6 l; C, F
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
0 {7 Z7 H( a( H- R/ L: `1. 高并发下单时,减库存量时要加锁
1 k% _& U& B" ^6 j/ b2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    ) u0 y" `* i, r& u+ d
  2.     模拟秒杀活动-- 商品100件8 M( [. Y$ {& B7 E/ o$ c7 |. {
  3.     CREATE TABLE ta
    + N9 `" q+ h5 ?9 ]2 B
  4.     (: x8 D; i& Z/ X* A" m
  5.         id int comment '模拟100件活动商品的数量'2 Y, l- Z/ \$ ^3 j6 ~+ D
  6.     );
    7 @9 x) A" X: m' y( V. c$ B7 ?" N3 M+ R
  7.     INSERT INTO ta VALUES(100);
    + S2 V# I6 y) o' P) D
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    3 d$ {$ M; f  I/ l' l
  9.      */
    1 _) j0 j6 {9 R' Z! k1 V; c1 z
  10.     2 |6 f0 T) q( f7 z3 s5 l' R8 i
  11.     // 关闭错误报告% Z) M! d0 n/ v7 _  E" m
  12.      error_reporting(0); ) y: v7 R& L. Q2 u
  13. 3 {+ z9 p3 W8 U7 s* `! z
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址9 l- O, c0 H  S# ]# T) I" r5 x
  15.     $dbuser = 'root';            // mysql用户名1 }1 O6 K: f8 V2 U/ E4 G
  16.     $dbpass = 'root';          // mysql用户名密码, ]& @4 }+ d" j/ M. Z  S7 c$ x
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);$ u8 [4 Y1 X9 E% ?2 p
  18.     if(! $conn ); c# J- U1 ~$ J& G$ S# N7 |6 A
  19.     {3 o& `8 s" D/ O* p# O8 l6 D
  20.         die('连接失败: ' . mysqli_error($conn));/ N3 \- v5 Z, O/ y
  21.     }8 o1 v/ c/ q5 `" M; x1 C
  22.     // 设置编码,防止中文乱码" _8 m/ M" z( D% m
  23.     mysqli_query($conn , "set names utf8");
    * Q1 b, a9 h7 @: q9 h* K$ u
  24.     mysqli_select_db( $conn, 'temp' );
    ' d1 H+ b+ \2 k2 I
  25. . Q* y7 t& ]7 e3 ]
  26.     # mysql 锁
    8 g9 t# e9 T4 y; u' u
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 * v+ w( T/ A$ P1 z/ o- T% @
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    $ M  ~" j9 R6 o+ }5 ^$ C( [5 j) @" A
  29.     $id = mysqli_result($rs, 0, 0);
    8 K  v" N) h5 h
  30.     if($id > 0) + j9 t+ m5 M9 V  Z5 |
  31.     { 1 T9 b9 W1 T0 s
  32.         --$id;
    # _; O, T; e* ?+ q2 @- d
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    - u4 l6 U8 K4 d; R; c
  34.     } ! Y& u9 e# j- [8 t! |9 v( d1 V
  35. , P, w: h  D4 A5 {. H9 |+ k5 A
  36.     # mysql 解锁
    ) k* l9 o- y+ H* N& c$ _, o
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    7 i. l" l& w0 v  z; M' _- m
  38.     //查询解锁后的id值/ s9 n* b4 a6 A1 Q5 @- [# Y/ {3 G
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    7 M- n. R; L$ p9 Y. L/ `
  40.     // while($row = mysqli_fetch_assoc($res))" @& \6 b! m( P  x6 a! X- G+ x
  41.     // {0 d1 D; o! s0 d2 X, t. r
  42.     //     $id = $row['id'];$ v. k! W8 s1 g, |' {
  43.     // }
    0 [1 w7 K7 l; _
  44.     // echo $id;
复制代码

0 f- h1 E( A! H0 p
: G3 Q' ?3 S/ V5 O
' M2 R# d9 X. c% o. p$ D, `
PHP文件锁示例:
  1. /*% i4 c0 n( k9 m# c) h5 R  L& M$ h
  2.     模拟秒杀活动-- 商品100件
    5 V0 P! A) j) F6 v4 D1 I  j8 ?
  3.     CREATE TABLE ta
    1 ^9 n( n4 _  h4 Z) w: w1 I
  4.     (
    2 \6 w: N9 Z0 k- ^% A) J( T0 z& j
  5.         id int comment '模拟100件活动商品的数量'# a$ j* j+ b, t) R: K9 i8 B5 O! P
  6.     );% V/ j# z5 `3 h7 j; S' w1 Q+ E8 O
  7.     INSERT INTO ta VALUES(100);
    ) a! v- [7 }- R2 L4 k
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    , q4 ]( n3 d2 S2 R5 K# Q
  9.      */ 1 s  h" ]4 u& r8 R; L# ]3 g
  10.     ' z4 X7 s2 P" j( ?# y
  11.     // 关闭错误报告& C6 e1 R% l$ M" b# t
  12.      error_reporting(0);
      ~% E; N* h6 e9 A0 K
  13. ! r3 X! N. @9 m" B: V" B0 S
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    * n( Z! a' v2 L) M
  15.     $dbuser = 'root';            // mysql用户名
    & r5 Z1 W: m" }; S- Q- o$ O5 r) t
  16.     $dbpass = 'root';          // mysql用户名密码9 M; g3 L" v$ \$ b6 N
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ( t# N; }9 N4 l
  18.     if(! $conn )$ O5 G1 _2 c: e) l- s$ K' P
  19.     {' h' [% X8 L: E1 u* L  X
  20.         die('连接失败: ' . mysqli_error($conn));
    - ^4 M$ M0 U' w) X5 G' j4 c1 Y
  21.     }
    & o5 Y+ r: A- J
  22.     // 设置编码,防止中文乱码
    * K$ L5 b- @% P  n% A
  23.     mysqli_query($conn , "set names utf8");
    * F$ Z# k) X% l# p
  24.     mysqli_select_db( $conn, 'temp' );
    / ?5 s3 z* h0 S% p) i/ C9 j9 s3 z0 s
  25. : D2 W  [4 a8 l0 R2 T0 \
  26.     # php中的文件锁
    / h4 p0 {+ M$ p. E0 h
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    6 r$ H5 g" Q! f$ X+ A/ B' H2 K
  28.     flock($fp, LOCK_EX);// 排他锁
    + T0 `2 n+ D- P: B& V* d

  29. % w4 K% Y8 S9 s" ?( i' g, [
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    0 |& m: u1 j7 r  L
  31.     while($row = mysqli_fetch_assoc($retval))
    * d0 g6 u; a* g
  32.     {# \- Z- ^' ^1 E- Z' k2 v5 x- G" \
  33.         $id =  $row['id'];" L  }+ l- |8 B: S
  34.     }/ C# j( k8 S/ s6 }' J
  35.    
    1 V. m6 O$ p$ Z* f3 z- E! o
  36.     if($id > 0) . `) v" S; v! F7 _; L; R' M+ H
  37.     { 8 Z* Z/ c/ h* S1 t* x0 q" Q' h
  38.         --$id; 8 V$ u0 P- g" b
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 5 R7 Z+ `# b; `
  40.     }
    8 j2 m( j3 W6 F$ b% v
  41.     # php的文件锁,释放锁
    ! M. o5 Q  K: D( n# O5 V6 g( f
  42.     flock($fp, LOCK_UN);
    ; v, D& g: @' h  I/ K
  43.     fclose($fp);5 x( o/ i& m; m( H/ X% ~

  44. " _* {* S7 O2 Y" N9 Z+ z" s
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    $ G! b% V/ K, ^" C7 V) l) Z
  46.     // while($row = mysqli_fetch_assoc($res))
      ^: T4 V# f2 A7 ^1 ~
  47.     // {/ D0 U  M8 z8 d( n* o# @* z" y- f
  48.     //     $id = $row['id'];: \) C, c+ U/ Q
  49.     // }% S0 g& X" u% x/ M( q$ M) T
  50.     // echo $id;
复制代码

. [0 |5 m& E" _
$ Y7 Z, V5 o- R+ m5 b
抢券活动实例:
  1. public function envelopeSnatching(){! T7 z+ p5 m6 h$ J5 o
  2.         $lingqu = $_POST['type'];4 q  w: G) q5 O7 }
  3.         $uid=session('u_id');//用户id
    ; n# v4 u+ n* ]- Q+ Q# }1 y
  4.         if(!$uid){
    * a) K( |) V  ?! D7 @$ C
  5.             $data['msg']='您没登录,请先登录!';* Q! K- H, R8 _4 B2 W
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    7 ~& _6 h) b# r& x. f- s
  7.             $data['msg']='不在活动时间内!';: ]/ ?' P. _& H5 H4 n
  8.         }else{$ s. C- q; |4 ?: {8 f6 ^* F
  9.             $hours=date('H');//当前小时数2 J+ k0 b: ^+ ]6 W3 A/ Q
  10.             if($hours > '09' || $hours > '17'){. }, j% P6 H9 i
  11. 2 c6 C6 _. Y1 k* {6 a5 K. g9 N0 \
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    6 z# q" n# j# |
  13.                     if($lingqu == 1){
    0 q4 u! D. O5 x
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过* A- F! Z: v! q, g! ]9 h
  15.                         if($hours > '09'){
    ! y$ z9 T/ Q. l4 a
  16.                             $num=mt_rand(25,28);//优惠券金额
    ) m) p4 y+ t) r7 {, Q3 X
  17.                             $id=1;! w' q* v8 ~1 X! s, p' ~
  18.                         }
    0 L2 J8 a+ v5 u# f
  19.                     }else if($lingqu == 2){
    1 c  H* f( j. y" [
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();! K- e2 v; H9 o" X# K7 s, L
  21.                         if($hours > '17'){
    % K/ }( F  q2 k- z7 ]& ?
  22.                             $num=mt_rand(50,55);//优惠券金额
    * f/ ~) g+ I! P* Z8 x: t3 U
  23.                             $id=2;+ z& Y! b$ u& Z) _1 k
  24.                         }
    / G* Z- R! l! O8 c
  25.                     }
    0 C* _' e: h: ^4 I4 [0 T
  26.                     if(!$id){
    4 }8 Z( d; D$ K# ?) Q
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    ; v5 X9 m/ Q- X
  28.                     }else{
    : q1 L9 I( Z  g- E5 F/ S
  29.                         if($is_lingqu){
    ( I8 O( O; T6 B" y
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';$ S9 }: u' ~; q3 c4 g* Z8 }7 c
  31.                         }else{+ q2 z# g1 j6 z+ S, p
  32.                             //锁表3 T" c; }8 R6 n7 q! o% I
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');: t) `# D: k2 ~( @2 C# M& C" w
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    # b* t* v' f  q* j9 D
  35.                             if($active > 0){+ o: G8 A' H" U: Z; g& ?
  36.                                 //开启事务
    % @- {! P3 f; S1 c3 {
  37.                                 M()->execute('start transaction');. c6 h0 o  |6 `# i0 _2 T4 G
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));" B1 c$ h9 z2 X* r* |
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));  w" u( ~% R+ Y3 M# e# |( N
  40.                                 $members_preferential    =    M('members_preferential');
    , u+ m- C7 j- ]1 M. E4 z0 Q
  41.                                 //对应投资金额,+ Z) H: K7 l& A7 j6 Q
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));4 Y/ c. h7 X. @2 K
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');+ J0 F# ~6 I7 d; |' O9 I* C4 p2 U
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间! O, E' W9 Q: `3 ?- C% M
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券6 J4 L) Z! e4 K9 q" ^
  46.                                 if($save && $add && $add2){# V- p6 T4 ^2 U
  47.                                     //事务提交, e8 _3 \: w1 H# `
  48.                                     M()->execute('commit');5 y# A, q2 {7 S/ \3 e% W# o9 F4 k
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';. b' l& a0 F3 m3 _! K( p
  50.                                 }else{
    : p1 n5 y+ s' D1 x% |9 p0 S
  51.                                     //回滚8 y4 I/ Q+ l& C" ]9 E* I
  52.                                     M()->execute('rollback');
    ( _7 f5 r: {! \
  53.                                     $data['msg']='未知错误!';
    , V$ I6 @6 X, h1 B
  54.                                 }
      C0 ~7 Z" H3 n/ m$ r
  55.                             }else{" @4 |& S; y3 G* n) T. ~' C) h
  56.                                 $data['msg']='红包已领完,你来晚了!';
    5 T, K; `4 x2 |6 O
  57.                             }$ o- @! G+ _2 K. p" A: F" o# k% m
  58.                             M()->execute('UNLOCK TABLES');
    # X9 L, ?' h0 v( `& C
  59.                         }: E  D7 @7 q( O- _
  60.                     }, F( o1 [! {* v" S7 t* J* r
  61.                 }else{
    - U4 W, q  u; P, P, B6 a3 Q0 d
  62.                     $data['msg']='非法操作!';
    , B7 C/ z1 m. g' c  ]* Y
  63.                 }1 _6 o- |: I9 {, T; h1 e' P  `8 D& f
  64.             }else{$ K9 f: }- x5 Q4 w7 J; D
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';; J! x6 }! n5 ^3 s( V
  66.             }" |5 O) F! I7 N' K, M" N2 U
  67.         }
    ' s* Y4 v) G9 d
  68.         exit(json_encode($data));0 l8 E" y! e3 x* W  q# c* }6 D
  69.     }
复制代码
4 W2 I0 q* L4 S: w" i

0 X2 f' `4 L( Q" n* L, o, k
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-4-26 22:31 , Processed in 0.133492 second(s), 29 queries .

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