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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9345|回复: 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://请求的脚本
复制代码
0 [: e* R( w0 I# w" q4 i
Mysql中的锁语法:# [" F' O0 U% p1 r4 e
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】9 N, W* R6 L) b
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
+ m" o( Y8 x5 m) z' TWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
% {/ |! X/ ?( O( n& p注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
3 `, C: \% V( M! z, Q+ P9 i文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。6 z9 C9 C, b% T" H( t9 K
测试时,有个文件就行,叫什么名无所谓
总结:
6 m) I8 J  x5 w7 v项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:+ F- S7 m* j; L" b
1. 高并发下单时,减库存量时要加锁
1 B3 l1 a" J; f/ b3 E$ y2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    7 ~* R; _/ j# }) X# V
  2.     模拟秒杀活动-- 商品100件8 t! K$ e1 g+ U1 Q3 t
  3.     CREATE TABLE ta
    / ?5 ?$ a& i2 t8 I1 e  ^/ Q
  4.     (1 P7 Y- w' L6 T6 y9 S
  5.         id int comment '模拟100件活动商品的数量'4 _' ^! T; W' U# |# |: Z( \2 p
  6.     );5 T* a, N# @* c% W/ w! j
  7.     INSERT INTO ta VALUES(100);
    : I6 p& Y8 [4 K% {
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    : Y1 ^& c1 y% [9 P0 T
  9.      */
    8 h. C- _/ `3 @1 {9 e
  10.    
    % ~5 h3 N; k- E0 r7 ^
  11.     // 关闭错误报告
    : D8 c/ c3 F' _! i, t0 \* x
  12.      error_reporting(0); # P) J+ |( e9 ]

  13. ( @& u4 W2 W3 r* q# {
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    + s0 L* v) _. ?. s
  15.     $dbuser = 'root';            // mysql用户名
    # Z" X2 K. H' M7 m; N( ^# B
  16.     $dbpass = 'root';          // mysql用户名密码
    , A( e$ N: r' B4 K3 M
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);$ R6 T; [% G8 u# u8 b
  18.     if(! $conn )
    # ?9 ~) w& R2 d$ K$ h
  19.     {
    3 J. f' k0 `) \6 d, x6 Z, {4 d
  20.         die('连接失败: ' . mysqli_error($conn));4 C! K4 o1 }' n4 c$ U
  21.     }# l( L0 p' A+ N1 e, V
  22.     // 设置编码,防止中文乱码
    2 Q# J0 m' J8 G% n5 R5 V4 T
  23.     mysqli_query($conn , "set names utf8");
    + T) t+ D  Q( p* ]1 Z- i1 ]
  24.     mysqli_select_db( $conn, 'temp' ); ! z) I8 k0 w. p% R6 C! q3 a$ P8 ]

  25.   \, x3 p8 W1 g0 I* I  F
  26.     # mysql 锁
    * M3 [) D( e# x; v
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    + b' e1 h6 {! z! t/ r
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    % C) R$ g  Z9 h( C" C" x
  29.     $id = mysqli_result($rs, 0, 0); - X% U5 Y5 E3 A" @; h# h( f
  30.     if($id > 0)
    5 i- E% a2 ]4 y6 y9 B9 s3 Z# X6 I
  31.     { 1 G" N( C1 m' y
  32.         --$id;
    ' \: }) e3 k5 b# T2 x8 K* Y
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); ( E, J$ `" f9 ]6 J/ h/ f
  34.     }
    ) A2 [9 U" U" b9 G( _: T0 E
  35. ' |+ N# g0 H6 j) }
  36.     # mysql 解锁
    + x1 }: B9 g" K9 d; R8 `" G
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    3 z6 o5 {+ K( C. f, Y- a) \1 G
  38.     //查询解锁后的id值
    4 d$ A4 ]2 H: ], O: Y, l+ j
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ! z3 ?3 W5 ?, d1 Q% A; S1 i
  40.     // while($row = mysqli_fetch_assoc($res))
    # X0 }& N3 d: @3 s! J! V! p
  41.     // {
      g' a- U  R* N! J& n( c$ {
  42.     //     $id = $row['id'];
    ) a& ^6 ~/ V) _$ |" U
  43.     // }  s% T' o9 r' m' l5 j
  44.     // echo $id;
复制代码
0 I2 H3 O8 ]2 N% v; @( i' H$ n
/ ~5 s" g9 n) i" u
0 v( n' m$ A  ^4 Q# L* b
PHP文件锁示例:
  1. /*
    ' X, [) j- T& D% T- i
  2.     模拟秒杀活动-- 商品100件: A9 u9 O3 X& @; b1 Q5 w
  3.     CREATE TABLE ta8 i1 M& N$ H9 K6 ?0 X% z
  4.     (
    ( ?* e/ X) p. X( n7 x
  5.         id int comment '模拟100件活动商品的数量'% ~5 p9 X7 T5 t2 U
  6.     );
    + }  ^2 @, m7 a8 p& q- u9 N% A
  7.     INSERT INTO ta VALUES(100);
    # J# J4 [* _9 u. b- m# z2 [
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件/ }0 ~2 r4 C: G. }
  9.      */ + \6 m4 L: j( @$ J( [. f+ q6 u& w
  10.     $ ^3 u2 D9 {" K8 W5 c' G
  11.     // 关闭错误报告, b* x2 i. Y4 `9 s. k
  12.      error_reporting(0); : D  }3 s, W  y0 O/ t% r
  13. & i# s' f' H1 q4 U
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    & ?+ D: _  f! S  K* ~
  15.     $dbuser = 'root';            // mysql用户名- I6 _/ f9 a3 B: @! u# d. p
  16.     $dbpass = 'root';          // mysql用户名密码/ {' f9 m% |' g! s+ a
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);. {9 w: i$ T0 V0 E, L$ y  ^+ J3 q
  18.     if(! $conn )0 f  N5 i5 |* ~* }( Z4 H' g
  19.     {- h, W& w4 e: Y: E' N; `; B
  20.         die('连接失败: ' . mysqli_error($conn));
      E3 ]0 C7 s& r7 t, b, f0 D
  21.     }* \" P3 J: p% @2 r
  22.     // 设置编码,防止中文乱码
    $ G, {6 s/ O! N1 M" M+ P
  23.     mysqli_query($conn , "set names utf8");6 i0 d' d. r) [
  24.     mysqli_select_db( $conn, 'temp' ); 4 N- z& A5 O6 a& X' y1 A# r  M

  25. $ g4 h9 `; |6 J+ o# J: T* M& M
  26.     # php中的文件锁
    9 a: O1 ^3 |* I6 }$ J$ D' \6 }' V" m
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 ! l- z6 C* M0 {) S7 v
  28.     flock($fp, LOCK_EX);// 排他锁
    " d" `; F. F* R) x2 O( O) g

  29. 8 w9 s( c) U# u: i
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ) b' _& I% l  O8 f1 h
  31.     while($row = mysqli_fetch_assoc($retval))
    , Q* z- l+ N9 M* t# t7 C
  32.     {. o5 @, D, H. S% N& _, [
  33.         $id =  $row['id'];
    9 b7 ~+ J" ]. {: \9 V
  34.     }
    ! _3 m( w$ `4 H4 f
  35.    
    * k1 f& E% Y: h/ n
  36.     if($id > 0)
    4 L/ P) t' m7 }' u6 S  d; J
  37.     {
    8 W6 _3 z! d2 b
  38.         --$id; , b2 X4 z( \% v- ^, ~9 a" q# ^
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    7 D* s1 `( f; X
  40.     }
    # m* b; `0 r* S  z
  41.     # php的文件锁,释放锁 0 J, B4 p6 e7 W' d/ C2 N' Z5 _3 X
  42.     flock($fp, LOCK_UN); 4 x2 U/ r' E3 F1 K" R( v
  43.     fclose($fp);
    6 I! P2 z+ _8 p# @& ]

  44. % U& \! ^9 G8 s8 d2 |, e
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');4 B( G7 A! }* J' s
  46.     // while($row = mysqli_fetch_assoc($res)); Y" ~  @# d  A1 ^, y+ a- }
  47.     // {3 ~  I9 z3 ]' a3 i( _3 v* M
  48.     //     $id = $row['id'];# }) R$ |+ r: U- Y0 m
  49.     // }! h; l& h# Z+ j
  50.     // echo $id;
复制代码
/ k+ q/ R# @. I- D8 R- r
; E' I- n% r. e
抢券活动实例:
  1. public function envelopeSnatching(){# |! A, N# v2 f7 q: a
  2.         $lingqu = $_POST['type'];7 ?9 l2 u/ r- n$ X% h! ~  N
  3.         $uid=session('u_id');//用户id
    " i- {! w% I" T+ I
  4.         if(!$uid){/ C7 ~( K7 f( u- o5 i1 @' I$ I- Z
  5.             $data['msg']='您没登录,请先登录!';
    0 _2 k; s! R6 X- ~4 j+ v
  6.         }else if(date('Y-m-d') != '2017-12-12'){' R" S7 c3 @) n$ M0 l
  7.             $data['msg']='不在活动时间内!';
    4 m  {+ Y* @+ y) v
  8.         }else{
    7 W9 Y: R6 }$ M
  9.             $hours=date('H');//当前小时数
    1 h" C8 q4 N2 }* Q' N! ]( K0 n1 {
  10.             if($hours > '09' || $hours > '17'){/ x; O" U* E9 P- H6 f7 P9 }
  11. $ V0 j; b# D. w* u' ?% O
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    9 A% f9 c, x3 V3 i0 U( p" o
  13.                     if($lingqu == 1){; X: n- J. N$ W
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
      I" B1 ~& B  R* H+ D1 X* `
  15.                         if($hours > '09'){
    , X& h/ C" Q' k( E
  16.                             $num=mt_rand(25,28);//优惠券金额2 t# P) a) V2 P. A! _, I5 {
  17.                             $id=1;& k  i0 e! d+ V5 L1 d( Q
  18.                         }$ d: U3 X: x9 p, J% U
  19.                     }else if($lingqu == 2){
    ( u  E) s0 ^3 {7 o
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    # {5 w+ I9 t) A5 I  J$ G# ~, q
  21.                         if($hours > '17'){
    5 n  F$ r- N0 h& ^9 Z/ a. }$ m
  22.                             $num=mt_rand(50,55);//优惠券金额! [1 B2 k1 |) [& R' a- A5 D: I
  23.                             $id=2;' o6 ?9 X* u" @* f3 [  `
  24.                         }
    , S1 L- s  ]9 c+ P2 I
  25.                     }/ s$ w5 |  D$ W( v
  26.                     if(!$id){
    7 B, @' e0 S* v8 h; o  m8 C
  27.                         $data['msg']='时间还没到,晚点再来吧。';# |+ p  X. z/ y
  28.                     }else{  G$ X1 r9 k& c9 l5 H
  29.                         if($is_lingqu){. @) r4 `' m. B( a& b
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';* [; V. v: w1 q" U& Z1 J; ^$ w
  31.                         }else{
    ; I9 I0 w4 H3 Z' C- q8 N& W
  32.                             //锁表- o; v7 ^  o) q$ i" m; Q* T  f5 T
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');$ P7 j- x6 E6 j$ d$ u9 A# Q
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();; i4 o: e3 f& Z. M3 o/ u( c
  35.                             if($active > 0){2 t4 Y) D4 X; c# z5 R- a
  36.                                 //开启事务
    & ]7 K3 A- H  T
  37.                                 M()->execute('start transaction');; A. f8 k7 h  O- c' L! Q! l
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    8 t/ a, T4 D# ~
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));. e/ A" S) \: ]5 @! n& @+ _% w& q
  40.                                 $members_preferential    =    M('members_preferential');( @# D/ U! V* U2 U
  41.                                 //对应投资金额,
    0 H. M1 R& w0 [: j" w
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));6 M9 ], E' o$ t  O" t* S$ o
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    ! F+ Z3 A3 H; _/ C
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间% [% A* t$ U3 @  j- p4 c2 u
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券* ]: T) ]& L4 ]5 j5 }5 U, j3 i
  46.                                 if($save && $add && $add2){
    / _& h3 b2 w$ h7 ?# u  N4 v
  47.                                     //事务提交
    5 l  U: C; x" S
  48.                                     M()->execute('commit');
    ( Q) ?" }5 B# ]( [4 o
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    4 C: M+ E$ c% v
  50.                                 }else{
    4 q0 T; @8 l& g! o8 Z3 r9 D3 o1 \
  51.                                     //回滚. [- Y% B& m/ c
  52.                                     M()->execute('rollback');
    8 v5 P* g6 v6 ^& G# z
  53.                                     $data['msg']='未知错误!';" R4 H' b/ [7 g( s% f) g
  54.                                 }
    ( }4 N2 D# P5 P. J
  55.                             }else{: S* E2 X: v* ]% J$ [; D( y0 k; G: _
  56.                                 $data['msg']='红包已领完,你来晚了!';. z: O  G& ]4 U0 Z0 D7 ]
  57.                             }
    ; F& r, W! |+ N! f
  58.                             M()->execute('UNLOCK TABLES');
    + g) W! _5 d0 E3 M  k* k' Y
  59.                         }  o3 n7 z& }7 H3 Z
  60.                     }8 f' V1 u# h! G. c* ]8 ^5 P
  61.                 }else{) s" k2 [1 F2 z6 K! Z
  62.                     $data['msg']='非法操作!';
    2 a  i5 B/ R9 r8 g; ^4 B
  63.                 }+ I. x  r/ I3 K2 T1 V  z; j
  64.             }else{: X1 k. c( o3 a% B6 z& c$ q
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';1 Z/ @: Q5 |: O7 l; _# z) w
  66.             }  }' @) Q+ F0 {% o2 H5 {/ Q4 Y
  67.         }: Q) V2 X9 l1 r5 F0 G; ?1 M3 b
  68.         exit(json_encode($data));. O* d' U" A0 H6 Y8 g0 b( A7 \
  69.     }
复制代码
& `/ N" n3 }' f7 D2 \

0 {8 Z% o2 X% N  j
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-5 01:03 , Processed in 0.054667 second(s), 20 queries .

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