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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9329|回复: 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://请求的脚本
复制代码
" S# v$ e. z% |3 e
Mysql中的锁语法:
7 J( |$ C2 b- G( x+ X) FLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
' }2 A4 Z4 t9 F8 I1 Y. @UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
2 p% o% ?2 @6 r( H6 x1 N! @3 V0 PWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
! }% y8 _. Q0 C2 X. e/ ]注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
( V. ]8 B6 d2 r) `7 P文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。# u" F/ l- l4 X5 H2 I' p# q
测试时,有个文件就行,叫什么名无所谓
总结:) B( M& L/ ?1 k9 t- i
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
, s5 }# t" S3 {4 z8 V* G1. 高并发下单时,减库存量时要加锁
* x6 V  h6 [3 y& ?* @5 G2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    8 w1 c# I/ f' Z$ X. T
  2.     模拟秒杀活动-- 商品100件
    * x5 z2 Q! V4 j* Q
  3.     CREATE TABLE ta
    ' i9 l' }2 [' h: ^2 N7 P
  4.     (
    $ T0 K  m. p2 m% D: C8 u
  5.         id int comment '模拟100件活动商品的数量'
    3 T' N' J9 m7 s0 _' y6 W
  6.     );% T' c  [; k1 K4 S+ c3 x/ ?
  7.     INSERT INTO ta VALUES(100);
    * _8 w: f! {  l$ u+ i; O( f0 i
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件* N' L) W; H$ C/ c9 Y* V8 }
  9.      */ 9 B+ d! D$ x4 \2 C$ t. m$ J
  10.    
    9 N# M; ]0 E$ w) c( G
  11.     // 关闭错误报告
    4 C. X; z+ z5 k: I# Y$ |* k
  12.      error_reporting(0); 7 ]" X; c& ^8 t6 Z0 N" N5 ?" ?. G: s

  13. 0 `6 N3 }2 {1 C1 {8 ]
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    # f) H6 `. s4 X% J3 U5 T
  15.     $dbuser = 'root';            // mysql用户名
    % a! Z: T" Y& g1 c! H8 f
  16.     $dbpass = 'root';          // mysql用户名密码4 Q+ Z- h8 x* Q4 g8 p9 d
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    1 o( w/ n, ?+ Z& I/ C8 N3 Q0 R
  18.     if(! $conn )0 U+ o9 W. L; l) k% {/ B/ D) D
  19.     {) S1 I1 X0 R# e
  20.         die('连接失败: ' . mysqli_error($conn));
    , T$ S, F( j, j  N8 X, Z
  21.     }5 R* D4 j1 c" k2 u& `9 @; ]2 ^: Q
  22.     // 设置编码,防止中文乱码
    4 i3 b$ E- w4 F' \7 k" Z
  23.     mysqli_query($conn , "set names utf8");7 f4 h* `& e' b2 C- U* ?/ m
  24.     mysqli_select_db( $conn, 'temp' ); 3 {1 [* C. w9 x6 J/ p/ ]. o# K

  25. 8 ^$ c4 G- H8 t
  26.     # mysql 锁 , ~) g8 |! B! T5 D6 L
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 8 ?' F8 l* h+ P- u
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); . q' N8 F$ @2 b, j
  29.     $id = mysqli_result($rs, 0, 0);
    % U2 `: @' G" H3 ?) t2 C2 y* F
  30.     if($id > 0)
    ' H3 F4 D9 V7 T! e, j/ C) U
  31.     { 4 k( z) [3 i0 ^& V2 \; f
  32.         --$id;
    2 S0 H, Q2 o6 `" ]
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); # L( t' t# }: @
  34.     } 3 \& @9 [( l8 \" Z) D
  35. 5 m* C, n. J$ P% C! l
  36.     # mysql 解锁
    % T; ~0 X$ S+ c; d, x
  37.     mysqli_query($conn , 'UNLOCK TABLES');$ V7 }" q( \5 |# X
  38.     //查询解锁后的id值6 ?0 Z4 g( j; m! v' J. H: x
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
      ]3 _. b# [/ w
  40.     // while($row = mysqli_fetch_assoc($res))% r1 |  H6 x$ Y5 u$ k5 L
  41.     // {
    : ]. A7 |2 x" g
  42.     //     $id = $row['id'];0 R4 ~8 L1 ~5 b7 n2 N$ W( d/ I
  43.     // }
    # G" q) ^2 W% O! R4 E+ c
  44.     // echo $id;
复制代码
5 t0 D* B6 z) B5 ~- A- T+ e

( i' A( h7 ^: Q4 ]! A

. B$ T3 _# A" m, V3 H0 i0 S5 y
PHP文件锁示例:
  1. /*# L: y* L) r1 g7 P" B; Y! X7 j7 {* F
  2.     模拟秒杀活动-- 商品100件
    & V2 l9 ^; b+ y- p+ _& s3 ~9 J
  3.     CREATE TABLE ta
    ( r' T8 i% s! r- u
  4.     (/ O$ q% ~0 `4 F, v7 ]& j( r8 o
  5.         id int comment '模拟100件活动商品的数量', T2 p; k% h% u
  6.     );4 c! s& y; H2 S) \5 [* A  z5 K' F: U
  7.     INSERT INTO ta VALUES(100);
    / Y& I0 B% `, H2 H$ ?1 {% p
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件+ _8 b  R, x6 w
  9.      */
    2 Z4 w* j- _( i% C# w- n9 ]
  10.     , x7 O5 K/ i" ?  ]
  11.     // 关闭错误报告
    # |  d, g& d; a, b
  12.      error_reporting(0);
    , x4 w( {9 _7 d! c3 J7 v4 O6 t

  13. $ U, m. q1 Q2 I
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址8 j! U1 \; u1 y$ e/ K' Y0 I
  15.     $dbuser = 'root';            // mysql用户名
    0 t& ]3 L* I% w0 x; z! a( s
  16.     $dbpass = 'root';          // mysql用户名密码
    / d% R! ^! @$ b. @
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);- t( ~$ x. z+ d7 `9 K0 X
  18.     if(! $conn )
    8 m; p& _5 ]# I
  19.     {9 J% v' Q- A, L! H2 ?
  20.         die('连接失败: ' . mysqli_error($conn));5 u8 Z+ ~* L" D0 E/ c% E% }$ Y* I4 B! F
  21.     }
    ) j) p: S" _: Q) {
  22.     // 设置编码,防止中文乱码) W5 Q$ K% ?1 ]* |# \+ i
  23.     mysqli_query($conn , "set names utf8");
    2 C! s& g# i7 j5 s
  24.     mysqli_select_db( $conn, 'temp' );
    5 J7 E3 N6 `/ H8 S; e  y! d8 d

  25. " i! |) }& o# w0 g3 a0 [
  26.     # php中的文件锁
    ! c; g1 V. Y$ U9 j6 t. E
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 3 r! Y$ O; W! }6 c) s! I
  28.     flock($fp, LOCK_EX);// 排他锁 ' `8 |- |* X* x( X. m
  29. 8 h; m3 R- a) i8 L" j7 m; \+ R* x( y
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    2 N2 U/ H0 z+ v& h0 G  ~
  31.     while($row = mysqli_fetch_assoc($retval)); V1 _. ~; z6 B+ A
  32.     {
    . Z; S4 a& ?  `( _
  33.         $id =  $row['id'];
    ! N3 h1 x  H- A; S3 @7 L" A+ o- l
  34.     }
    . A- _9 X1 b! J. M% W8 ]
  35.     ) U. z9 c$ P- M: \$ y3 E1 ]2 c( w
  36.     if($id > 0)
    4 J: b* H8 \& y; ?) f; d
  37.     { & y% j  ~( [0 g
  38.         --$id;
    . c+ b9 o) F; ]! b; |; Z, ]8 d
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); & q  A4 F, U. F' ?7 R+ z* B7 @
  40.     } & Y- A1 j; t8 h4 O& a
  41.     # php的文件锁,释放锁
    " n* u$ V3 w3 D& L6 C' b
  42.     flock($fp, LOCK_UN); / z! S6 o- x7 t
  43.     fclose($fp);
    - U  }! C+ z# N6 T! ]) T
  44. - T% \. O3 \! z: M3 p; r7 r5 B& W
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');- Z5 s, X1 E/ S+ k6 D+ O7 ^* V2 b  m
  46.     // while($row = mysqli_fetch_assoc($res))
    4 y) `8 D) R! Z" L' \! B. E) p& g
  47.     // {
    . u. d! D! L# ~3 W, M1 z2 |) y
  48.     //     $id = $row['id'];
    ! T# N5 V! k  O* I8 Y4 T0 W2 a
  49.     // }
    4 p+ e! l. V" C* F# ^; V
  50.     // echo $id;
复制代码

# [, S0 o  Y1 K7 I3 N
0 P2 \- T7 E2 M2 [
抢券活动实例:
  1. public function envelopeSnatching(){3 Y9 |; p5 s; {! r0 s- U
  2.         $lingqu = $_POST['type'];, B; s; {  H4 V+ H
  3.         $uid=session('u_id');//用户id6 `1 G$ d! p- Z6 ^/ _3 I; |2 P
  4.         if(!$uid){2 ?* L! d% j9 [, ^
  5.             $data['msg']='您没登录,请先登录!';
    8 v9 L% Y& y, E1 U0 u) S7 X9 t
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    " R5 m8 R" i" X: l8 d$ z
  7.             $data['msg']='不在活动时间内!';% \  B3 m( }4 X! F5 v" l
  8.         }else{: x4 G8 A6 i  V1 E" P% I( O2 X
  9.             $hours=date('H');//当前小时数$ B5 u' B& X3 c, m5 Z
  10.             if($hours > '09' || $hours > '17'){) S$ E' u+ F1 `1 l+ X

  11. ( I7 T8 D9 p; U
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的) ~0 G# X) x( V" b+ z% |
  13.                     if($lingqu == 1){" M6 E" r$ Z9 ?" I) I: ?8 [0 h1 l$ Y
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    0 g% H1 Z) s% a% l' ]6 s" j1 A9 a
  15.                         if($hours > '09'){
    & S* R% m7 {$ q* Y# D4 @4 C
  16.                             $num=mt_rand(25,28);//优惠券金额
    % n% s  C& {- @+ Z
  17.                             $id=1;4 u/ p+ h4 m9 P4 Q/ H, R& X, P
  18.                         }
    , A6 j- A" D2 H. Y9 j6 s2 d
  19.                     }else if($lingqu == 2){9 l, Q( j% S- g( C5 B  [6 d
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();2 Z4 i5 [7 `- B; X' K! \- d3 Y
  21.                         if($hours > '17'){
    8 b8 e$ s$ F' r
  22.                             $num=mt_rand(50,55);//优惠券金额$ G; D! X) W: ?. ^7 }2 D2 V
  23.                             $id=2;6 h5 x, e9 Z4 A9 v
  24.                         }; _5 [- s" n2 E$ Z! J# t: \
  25.                     }
    : p% x- G' k% e. H3 \
  26.                     if(!$id){
    ; I4 B: V% l$ M& x- C- W
  27.                         $data['msg']='时间还没到,晚点再来吧。';- P: ]1 L- X/ Z9 f
  28.                     }else{
    ( A5 j1 J9 B. x9 _
  29.                         if($is_lingqu){+ [! ~  Q+ b$ @" _7 Z
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';2 L/ a* g- z7 @# p4 o2 u
  31.                         }else{
    " X3 s2 l& t* Q$ p1 q
  32.                             //锁表
    - d2 B4 u$ z7 E) s- t- E6 p+ q
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');5 m( w( Z+ c6 e# K$ U( f
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    ' }7 d" f/ T& ?; M6 i1 l; ~
  35.                             if($active > 0){+ [7 \2 w! d- q' M2 e6 a+ P
  36.                                 //开启事务/ A2 _: K, R- [! E4 K
  37.                                 M()->execute('start transaction');; ~" M4 h7 E% J$ f* J  q
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));4 D$ ?' t  a& L5 ?* H5 W, Y
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    9 ^5 a3 ?. \. p* a2 k
  40.                                 $members_preferential    =    M('members_preferential');
    ; }/ Z! g4 t$ x' H8 Y/ F" k! Z
  41.                                 //对应投资金额,
    * U3 X# {2 t1 z; F+ Z( V/ d
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    # `, C$ H0 F3 \% Q$ A
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    - @4 l& m& D: R3 e( v
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    # m, R- m# N1 ~$ s& ~* i/ x
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券4 v9 H/ m* [) _. C2 ^/ i1 V
  46.                                 if($save && $add && $add2){6 }1 [  g, a  _7 C% V* W
  47.                                     //事务提交
    & T6 E* n0 r; ]  G- t  H
  48.                                     M()->execute('commit');
    2 c4 n% A% v" a; p
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';- b, A4 l- b& Z0 ?" O1 x
  50.                                 }else{0 Q$ c1 I: m# O1 g3 P4 ^
  51.                                     //回滚
    1 T* a' q; ^  E/ t, m
  52.                                     M()->execute('rollback');
    $ Z9 V& b. F2 S
  53.                                     $data['msg']='未知错误!';6 r9 Y4 a, [9 S% t/ g
  54.                                 }
    2 V# O+ ~& z* P$ y
  55.                             }else{0 {) X8 W, T4 ?) L) X& z6 U
  56.                                 $data['msg']='红包已领完,你来晚了!';% A% Q2 l0 a- E' D" @' o
  57.                             }" q) n4 f9 o+ ?$ z$ j
  58.                             M()->execute('UNLOCK TABLES');
    . S/ r$ \8 f5 b: ~# I. _' x0 m
  59.                         }
    0 f: v" |% D! l  I- @" a
  60.                     }
    # [0 S! g; e& D
  61.                 }else{1 s1 `$ T; u: r3 J* v
  62.                     $data['msg']='非法操作!';, J( O/ S0 b  d
  63.                 }7 ?; O4 R$ P& n* s
  64.             }else{  `/ j7 _/ u5 t1 [' n3 Y
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ; K2 p' t! l3 T0 ?& S7 U3 f
  66.             }
    ; m* S0 v( x+ k* p; d
  67.         }
    : h( z1 }& W) ]! n0 A$ F  B
  68.         exit(json_encode($data));! J3 K* ?8 l# H
  69.     }
复制代码

' ~- c8 r& ~* k
, C' _" P1 f: L4 ?: w! G0 o4 I
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 08:11 , Processed in 0.057852 second(s), 20 queries .

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