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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8886|回复: 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 |/ X. `) r% u3 s8 ]: G0 e! q
Mysql中的锁语法:
  b7 @5 ~4 M4 L: z) BLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
, ?+ {/ q( s- }UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表. d' e' F( ~7 h
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
& B4 \; I( M3 ~- n注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
6 X$ }8 L7 i0 i3 s) O# N3 h/ M文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
6 u. o+ z! T2 Z# l测试时,有个文件就行,叫什么名无所谓
总结:( F1 D% F& z7 g1 C- D: L3 ]6 \
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
" q6 |0 N6 S1 L/ k; g$ A1. 高并发下单时,减库存量时要加锁; ^* x. y9 D7 }' ?
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    " e! Q/ B, P9 A
  2.     模拟秒杀活动-- 商品100件8 j& c9 U3 s* l( ]0 y
  3.     CREATE TABLE ta
    ; Z, C6 S2 ]* X! M
  4.     (
    + B; q! c# _# e  y3 O2 e
  5.         id int comment '模拟100件活动商品的数量'
    2 g5 l9 [: F) l/ X
  6.     );
    0 }, w) V2 J' r. W; ?8 e3 d
  7.     INSERT INTO ta VALUES(100);
    ! Y/ G! f& X5 {9 }1 X4 [
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    # W& Q; |+ _  G4 F% P
  9.      */ # n% `: i, `9 A! i  \" f9 b" g
  10.    
    ! B! E3 n8 n0 O" t5 Q
  11.     // 关闭错误报告; k" e) Y6 i9 F8 k0 ?
  12.      error_reporting(0);
    , Y2 U) U+ U0 ]5 v3 y$ U
  13. / N8 g% S: S! ^/ r0 j
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* E/ J7 J, i; B  x  X
  15.     $dbuser = 'root';            // mysql用户名8 Y: c6 x& _8 }& \( p4 m
  16.     $dbpass = 'root';          // mysql用户名密码9 {- C: i4 J, c2 i* m! V4 }$ Q4 E
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    0 A  S* }& Q( i
  18.     if(! $conn )0 [7 k, T0 h8 O7 d1 B& l
  19.     {
    6 L7 Z/ H7 p  R' U7 z2 z
  20.         die('连接失败: ' . mysqli_error($conn));
    / n: x' B5 O' J  C) x
  21.     }
    5 i9 X. p: q7 j" H  Z
  22.     // 设置编码,防止中文乱码
    % q0 F9 U6 n0 X$ r6 @; ^8 e* s
  23.     mysqli_query($conn , "set names utf8");: F. H0 O0 T* n0 o' i* u* X4 N
  24.     mysqli_select_db( $conn, 'temp' ); ( Q8 F- ~% K' S" m) f  W

  25. . d( L" x% U) B: m: G
  26.     # mysql 锁 - r2 w  U' Z2 }
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 6 ~! j, d* t( ^9 v4 |
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    + t; u& p2 `5 i8 @1 G) K7 m
  29.     $id = mysqli_result($rs, 0, 0); & }" s* l* T- T% p
  30.     if($id > 0) 0 g2 T0 q# }+ J4 B% h1 U
  31.     { / D; R, \, y. w1 z9 n
  32.         --$id;
    # a: v# t, f8 _% c
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); + i- E+ R" c$ ~9 W$ |2 D
  34.     }
    . W0 W2 _. ]2 l% _
  35. 2 W& a8 {, |5 b+ }" w- @- O* ?# v5 k
  36.     # mysql 解锁 6 w9 I8 _5 d5 D8 j) V7 Y
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    " E  u7 i9 |* _4 d3 ^+ W
  38.     //查询解锁后的id值7 q4 e8 |& i2 I. E- f+ X
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');) x# S1 c1 N) ^9 ~
  40.     // while($row = mysqli_fetch_assoc($res))6 X8 N1 M- n, A5 m& z- n/ z) f
  41.     // {, A" }* M5 T0 X0 w: n8 Q9 M: d
  42.     //     $id = $row['id'];
    6 x  O6 G* A+ C4 [
  43.     // }0 _6 g& ^# w4 N0 L& k7 s5 {- F8 T- t
  44.     // echo $id;
复制代码

0 [$ [4 V+ ?6 q
1 X, h0 y9 H; n5 O; f

7 t: e0 M+ U+ q3 p' O6 J7 `
PHP文件锁示例:
  1. /*
    7 c% j9 v4 A& M; X, r3 X1 }
  2.     模拟秒杀活动-- 商品100件) J- l+ r9 w1 U/ Z7 Y
  3.     CREATE TABLE ta
    . `$ l9 T. l7 D, w
  4.     (: X9 W8 \. G5 E9 R5 v" r! W
  5.         id int comment '模拟100件活动商品的数量'
    3 K- O9 C9 c4 c
  6.     );
    5 Z. z+ A, T% s: n( j1 W; J" H7 s4 ^% ^
  7.     INSERT INTO ta VALUES(100);# d( K# d( `8 \9 ^9 U6 ?
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    $ T3 b" G: f& j% B& J
  9.      */ 1 ^3 P( H  [* e: ^' v+ C
  10.     4 w+ _+ {3 S8 A3 a; e
  11.     // 关闭错误报告
    + E9 X1 _/ V6 P8 E# [- {* s5 K. ?1 i
  12.      error_reporting(0); 3 `8 L3 m0 @2 j

  13. 5 _8 Z4 w! D6 {$ ?4 I& E
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址! H9 R. j/ e1 {3 t; l9 l4 n
  15.     $dbuser = 'root';            // mysql用户名( }: ^. G# p; m/ z  s* I
  16.     $dbpass = 'root';          // mysql用户名密码
    & J0 V8 [4 _7 e4 A2 [
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);" T4 c7 Q* [8 x4 o/ r1 {3 Y
  18.     if(! $conn )3 l0 Z) _0 c: C' [. d' d6 m. a
  19.     {
    ( }( C5 i, w- ?, [- _' d
  20.         die('连接失败: ' . mysqli_error($conn));
    # A) y2 ~% m; _6 s
  21.     }5 ~; ~# k: f# ~6 q0 v2 L
  22.     // 设置编码,防止中文乱码
    ' V9 h5 ~/ i5 [: j! p# k  X! g0 S
  23.     mysqli_query($conn , "set names utf8");) a4 \$ k; J" }. C- u
  24.     mysqli_select_db( $conn, 'temp' );
    ' }! O, h( Y0 W
  25. $ N2 t+ ]- {7 o  {9 u# T9 N
  26.     # php中的文件锁 3 I; K% y/ ]3 P
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 , [" |; l& h* p4 _/ V: Y) W
  28.     flock($fp, LOCK_EX);// 排他锁 + x7 m2 S5 g  m! H

  29. 9 O: [; ?. [* x! c! p
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ' p4 g3 B9 p& H, `
  31.     while($row = mysqli_fetch_assoc($retval))
    $ |2 C0 r2 h) T3 F# c, g+ E
  32.     {' y/ e, U! q- Y4 z
  33.         $id =  $row['id'];
    / C- Q$ p8 x( [
  34.     }. Z8 f6 ?! Y1 t8 b
  35.    
    * E8 Y; n  S: ]6 L
  36.     if($id > 0) 3 f( l4 C2 o& a
  37.     { 1 a& d, U8 L  E& B
  38.         --$id; 4 e/ V6 y4 j; b/ H
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 1 `9 N4 {3 w% q
  40.     } 1 T3 w& a0 B, j: X
  41.     # php的文件锁,释放锁 3 k% Q" H& U2 o% Q
  42.     flock($fp, LOCK_UN);
    # e, F" E* C$ }2 K9 t" A% B% {
  43.     fclose($fp);; l7 {1 G& Y9 y4 |
  44. 7 y1 {  P2 w* I. W
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    2 V! d+ `9 _2 }% f
  46.     // while($row = mysqli_fetch_assoc($res))
    ! K$ }0 I, K& L5 ~, J6 u* S6 V
  47.     // {
    # K+ X! f8 M9 O; M+ R2 I* D" A% T
  48.     //     $id = $row['id'];" R# H- P# S2 D6 u
  49.     // }4 b- U. z5 N/ u8 s0 q" p# k& ^( f
  50.     // echo $id;
复制代码

9 i6 W: e8 q6 l* L( a, p
  n; v/ @3 `9 B8 S/ P" J5 I
抢券活动实例:
  1. public function envelopeSnatching(){
    $ V5 X8 e, D6 u3 ^& Q. c
  2.         $lingqu = $_POST['type'];2 J7 f) c" B. i, ^( l
  3.         $uid=session('u_id');//用户id4 x6 u8 y) q3 L5 M) f
  4.         if(!$uid){
    ' i7 k5 `# F$ @! R
  5.             $data['msg']='您没登录,请先登录!';
    6 f! X+ p  }" H2 Y0 [" Y
  6.         }else if(date('Y-m-d') != '2017-12-12'){( ?. t2 a( T9 o
  7.             $data['msg']='不在活动时间内!';2 |$ Z2 r$ \/ V+ r& C
  8.         }else{; t; O! I; L6 L0 z) K, {* ^/ s
  9.             $hours=date('H');//当前小时数
    ) G' [4 g7 `- b. p8 i/ [
  10.             if($hours > '09' || $hours > '17'){" Y9 V. Y) J. H( d) R3 t% B
  11. & K; ~0 e$ e5 p
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    6 ]6 o  y5 u( O4 ?! L
  13.                     if($lingqu == 1){! }' x5 I. Q' X7 U2 s: b
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    * U) K( s4 t5 C( J
  15.                         if($hours > '09'){
    , V/ b% x. {6 v/ z
  16.                             $num=mt_rand(25,28);//优惠券金额& s1 `) J8 Z2 g3 g( B
  17.                             $id=1;( G2 e/ a6 j. _
  18.                         }" n$ R" i; M" K0 i) i
  19.                     }else if($lingqu == 2){
    - Y% z- E/ W4 f
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    % U4 c9 q2 o4 |) k
  21.                         if($hours > '17'){
    ; x' l1 G; x, Y' ~- n* i5 `
  22.                             $num=mt_rand(50,55);//优惠券金额
    4 e2 M0 P* m2 E8 h
  23.                             $id=2;% g2 ~( A7 X! r* y' ?5 n3 K( v
  24.                         }  H4 k6 I8 Q, a
  25.                     }1 ^/ b( N) G. }5 o5 t9 M. Q6 F2 j# M
  26.                     if(!$id){
    ' H$ y# [8 I) {
  27.                         $data['msg']='时间还没到,晚点再来吧。';3 _5 V. a; M+ m, c0 \9 L
  28.                     }else{
    5 g/ [3 a4 w9 @0 y; l/ d, P
  29.                         if($is_lingqu){! O4 x+ P* J& ^: S- W
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    - T: S! Z1 a; K$ e/ r* h
  31.                         }else{
    & c# z  o- F- A# L' X! N' g+ V
  32.                             //锁表( p- [8 D: B2 Y+ r$ _
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');1 C: x* w$ w$ B. k( [
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();& O5 `; @. w! }% d+ Y
  35.                             if($active > 0){' p: ^5 P+ j  l
  36.                                 //开启事务0 v" C  \% Q; s; g$ s
  37.                                 M()->execute('start transaction');$ i/ u( Z) f7 {; `2 N0 T
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));3 b" n- Z, p# N4 P6 t+ u+ u
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    " R( a/ z/ ?! e2 X: ~. r
  40.                                 $members_preferential    =    M('members_preferential');
      A" f& T! Z  _
  41.                                 //对应投资金额,$ {' D& R+ z2 d6 i6 `, y- W5 J# h
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));( B6 O, \; q+ n/ ~: F; [# H6 M
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    & ~- b, _7 p: }  f0 p
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间$ V4 _- v0 s3 j3 D- s) Y1 X
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    7 B2 X" N9 t; e3 C& |
  46.                                 if($save && $add && $add2){9 {2 r8 {/ F% x+ ~- L
  47.                                     //事务提交5 v8 z4 @, x( f/ R
  48.                                     M()->execute('commit');
    4 S9 b5 N0 P1 \2 j' t
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    ) G: X5 Q" p- D- o, ~7 G
  50.                                 }else{
    7 j5 X" g, p! _2 O" m! s( i+ J- L
  51.                                     //回滚
    $ g3 q& O0 |9 R; i
  52.                                     M()->execute('rollback');
    & _! R; f3 J% x% k8 R# e
  53.                                     $data['msg']='未知错误!';
    ( J9 i8 @, V- r" z) g8 x
  54.                                 }  G1 n& b+ c5 Z' |6 j  B- Y8 ^: i
  55.                             }else{! a, d; ~2 E. q* Y: r* d( J' [, C
  56.                                 $data['msg']='红包已领完,你来晚了!';8 m- B- J& D3 ?' l  D; q
  57.                             }  d( h7 u. L8 ?4 V
  58.                             M()->execute('UNLOCK TABLES');
    : r3 [/ r: D3 R; A$ {& C$ ~
  59.                         }
    9 k7 u, o0 e, {" i) Q4 P( E& u6 h
  60.                     }
    ( _+ U' R5 h4 q4 x# ~3 g/ q- g. L
  61.                 }else{
    6 n0 ]; d% ?6 F8 D2 g+ `0 N7 v
  62.                     $data['msg']='非法操作!';
    - v: a6 J3 ^3 O) i
  63.                 }
    ' e; ]( ]8 Z5 ]1 B8 s; Z% U
  64.             }else{
    ! p' O: e! o7 |( R' ~7 M
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    * X  g- ~5 s+ I0 ]/ h' P6 _# W
  66.             }7 |- q% L& Q9 s
  67.         }
    " M8 q6 F9 G9 ~. }
  68.         exit(json_encode($data));
    ! C& b: F9 f0 `6 O( \
  69.     }
复制代码
* H6 h/ U/ E4 {8 S" `

% y9 F. B2 [; x* r! ^$ m5 m3 G5 N6 n
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 21:07 , Processed in 0.061794 second(s), 19 queries .

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