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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3864|回复: 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 u2 @  i! H- \: @2 }9 }8 [
Mysql中的锁语法:1 g. B* b- _' z* w0 K
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】2 x9 x4 j; ^* ~, m8 A: t- E
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表+ v! u* H1 w- X" \; ]
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞( _. V$ z5 O8 h" S0 v* U: H/ l4 ^5 l
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :& `8 M& k/ q, i$ A
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。1 v0 j0 B( d* ]) c! @3 J6 n
测试时,有个文件就行,叫什么名无所谓
总结:
3 H1 Z- b9 D, G% ~+ L( q- M3 L) ^/ Y项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:8 Z. Q! g; R  E; c0 t& A! f
1. 高并发下单时,减库存量时要加锁
9 T6 E7 U" a; m1 \8 M. q2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*9 N9 N) V; B8 L+ d
  2.     模拟秒杀活动-- 商品100件
    . P% I* O' H3 f
  3.     CREATE TABLE ta
    1 z4 U* Z: G" e: l& ?7 ], q" N7 x
  4.     (
    $ ]( W7 b! X+ U  x, u
  5.         id int comment '模拟100件活动商品的数量'' R1 E6 L2 P$ A$ r
  6.     );
    - j  P. E% g; @
  7.     INSERT INTO ta VALUES(100);
    ' z0 `6 _: }# @' j* M
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件+ _: L2 T# D$ \1 N  V& r9 f
  9.      */
    0 n( H+ k  J. F
  10.     : P" _" B/ p9 g5 y, L: ]  S
  11.     // 关闭错误报告. J8 e: T0 Q  n- ], M
  12.      error_reporting(0); 7 |% z% R% I" r& N0 n

  13. 5 ]8 N" T3 q# ?1 X3 |! T0 g) r" k
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址# s1 ?3 T( d3 }
  15.     $dbuser = 'root';            // mysql用户名
    ; g2 [% ?; q/ A9 H' E" |
  16.     $dbpass = 'root';          // mysql用户名密码
    # _- ?6 W; ^4 F. N2 Z- J
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);* y3 N! A' K6 d: b9 D
  18.     if(! $conn )8 m, ?  R7 _5 b6 ^% @" H
  19.     {" C& o1 m1 w1 Y3 [" \1 x3 l7 H
  20.         die('连接失败: ' . mysqli_error($conn));
    ! j# A* r' a9 r: _  t
  21.     }
    0 Q! E% u- m7 P6 D, C; }. D7 C
  22.     // 设置编码,防止中文乱码
    9 s" q8 n! x( f" T! \
  23.     mysqli_query($conn , "set names utf8");
    * v$ P, s4 D3 A; F9 R7 F# A
  24.     mysqli_select_db( $conn, 'temp' ); ) z+ X7 ^  N1 S3 j

  25. # o- E8 f0 U8 z* @" d, N4 n
  26.     # mysql 锁
    : r* U' [# x; F' C) L
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    ) S5 q. z$ j% K) o) @) U* n% z  W
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    8 e1 `! C5 h: j. C( o
  29.     $id = mysqli_result($rs, 0, 0);
    " @5 y6 u3 i8 [  s
  30.     if($id > 0)
    # o! c0 m8 v& U; a) t4 j
  31.     { 5 g4 A$ X7 H; _5 A2 D
  32.         --$id; * G  T+ T2 s" K5 J: n0 x( S
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);   f' ^0 [$ |) a  }, a
  34.     }
    & W5 T9 A- t7 F$ P

  35. ! b7 w  A/ R8 ?1 v
  36.     # mysql 解锁 ! N% X8 w, Z, ^" ?
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    5 q' z' Q8 ]3 X9 ~% z" H( i
  38.     //查询解锁后的id值4 l% F) h, A6 y+ M
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    6 R+ u/ A  G( F  g& Z
  40.     // while($row = mysqli_fetch_assoc($res))- t+ w8 O6 F, W
  41.     // {' Z9 L$ G, ]. }  ~! n" A* N) |$ z
  42.     //     $id = $row['id'];3 p3 ~8 m( s: h5 {6 h% o* E; ?% g
  43.     // }. B/ q  `% K) ?. _. ]
  44.     // echo $id;
复制代码
+ f- X" W# }1 }/ B7 g8 P7 q
# y" [* H. s5 B

! y8 i' _( v. N
PHP文件锁示例:
  1. /*
    , @' O7 a$ ]$ _3 W' l
  2.     模拟秒杀活动-- 商品100件6 Q% `' u- D% ~+ m8 `& d9 ~
  3.     CREATE TABLE ta
    ! b5 v2 n: ^/ A' N, l
  4.     (
    * s2 T, R: g7 e2 a- v7 T
  5.         id int comment '模拟100件活动商品的数量'
    * x( f" F0 p) m/ h+ r) `6 k
  6.     );
    % F& s$ Q/ C% S$ _# `" `: b
  7.     INSERT INTO ta VALUES(100);
    & W) b* }5 Y6 a* I& k
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    6 D  @' G( w6 d! D) y2 h
  9.      */
    2 O) U# f: e2 h+ c1 C7 C
  10.     ; v, G2 A. z: Q& }5 @/ r
  11.     // 关闭错误报告) b- n: D3 r0 i* d% s
  12.      error_reporting(0); 2 i. T3 [$ ^* P) Y+ C; ~' G

  13. 6 |1 }) u" i5 W9 t- N- ?: U
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ) p8 q, N& X- ^  B) N; |7 F# \
  15.     $dbuser = 'root';            // mysql用户名: u) u9 _& r  p' ^
  16.     $dbpass = 'root';          // mysql用户名密码
    * q1 l% l7 H+ d4 K7 Y# `, g* _
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);3 u$ H; p2 p: G3 J/ r- N5 l* |5 y
  18.     if(! $conn )
      }$ |' K) K, h# Y  ~& }
  19.     {
    * E" Q4 w4 c: i* r% I8 Z  o. `# Y
  20.         die('连接失败: ' . mysqli_error($conn));
    8 h9 n3 t2 f# B8 K% E
  21.     }- t/ ?# k! i9 [7 M9 K
  22.     // 设置编码,防止中文乱码
    5 Z8 h" S# d5 ^
  23.     mysqli_query($conn , "set names utf8");
    + W. D1 c8 S7 ^
  24.     mysqli_select_db( $conn, 'temp' ); : w' U2 j/ r- g

  25. 4 D' P' l6 h3 t- b, T  {. X
  26.     # php中的文件锁
    % c2 z$ A# P; Y2 c% T2 R
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 : ~0 Z* _; _4 V5 S: t
  28.     flock($fp, LOCK_EX);// 排他锁
    $ I9 }% [1 i8 Z" z

  29. , ~# H& N9 Y& F. [5 U  s. N
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); . v$ c' I9 V% J% D
  31.     while($row = mysqli_fetch_assoc($retval))8 @% X- _5 h% I  H9 a
  32.     {
    ) k( |7 ^2 T7 J4 D: m
  33.         $id =  $row['id'];$ B: O0 [$ U3 N. z
  34.     }4 P5 \8 h5 K, M0 n4 t
  35.     $ @0 h) @6 Q  s- D% X5 _
  36.     if($id > 0)
    4 q, c( R# Q, N
  37.     {
    0 m4 J4 \- Y4 \2 E; a8 }; A
  38.         --$id;
    % Q$ @- a, q8 t# E9 Y) ?, N4 E6 g& G
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    + E) e6 L# k. @) l5 X* x/ i
  40.     } ) t1 ]6 y' j; a4 u8 a+ u
  41.     # php的文件锁,释放锁 4 e, A/ ?& D6 ^& t  K0 P
  42.     flock($fp, LOCK_UN); 6 |& B1 h  l9 B, `! W' U3 D
  43.     fclose($fp);
    ! b% p( z  n) w  j6 `
  44. % y- p0 x  i3 r5 E  o1 P# F
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');8 s4 J6 ?/ t8 m
  46.     // while($row = mysqli_fetch_assoc($res))
    3 b& [- p" G- ?& ~3 s2 W
  47.     // {: F& \. q* W8 i5 {- S" m
  48.     //     $id = $row['id'];
    9 G0 S! |1 f0 o$ A: `' w$ d
  49.     // }
    , @3 d/ t7 ^" C, c
  50.     // echo $id;
复制代码

' ~( R1 M  W& R+ I, G4 R6 J3 q9 b; s/ C, F$ ^
抢券活动实例:
  1. public function envelopeSnatching(){4 l2 O/ f! \+ w
  2.         $lingqu = $_POST['type'];
    7 ?  |1 n- t* q$ q! f0 L
  3.         $uid=session('u_id');//用户id
    ! G1 `' n! o% k5 l- A% \1 a
  4.         if(!$uid){. l) x* z7 j3 E! p
  5.             $data['msg']='您没登录,请先登录!';! t0 ?+ h! z2 G9 X4 R% D4 o
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    8 G( b" m8 S! r, F1 c" }
  7.             $data['msg']='不在活动时间内!';5 S6 c& ^5 L) q  f5 v7 S
  8.         }else{6 [9 b, i) o* \4 n
  9.             $hours=date('H');//当前小时数( _4 c2 c' ?1 u! |8 X" t6 v& ]% @
  10.             if($hours > '09' || $hours > '17'){: F" t$ V5 B& i6 i6 J& R$ ?
  11. 5 Y; k: c6 C' A/ E
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的+ ]7 E1 k' [: F4 N
  13.                     if($lingqu == 1){1 Z, F( B$ [5 q- y$ d
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过  {! L6 }' _  E. F9 I
  15.                         if($hours > '09'){8 t% ~+ Y3 S% F5 z! f% U7 D
  16.                             $num=mt_rand(25,28);//优惠券金额
    1 K9 m( U% u( y/ W7 _0 O
  17.                             $id=1;
    / ?1 S: F' N6 }$ {& N/ w
  18.                         }
    , O: Q" k  U  c1 N* L, X2 O" L. \+ f
  19.                     }else if($lingqu == 2){) w6 k3 N$ J( e3 P( R& s2 D! ~
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();( m; ^( m+ `+ K! p& R0 v
  21.                         if($hours > '17'){
    5 K  u) I- }) C1 C, u2 Y6 d: r
  22.                             $num=mt_rand(50,55);//优惠券金额) u/ Y& O2 b/ g9 y; i
  23.                             $id=2;
    " I1 A# ^1 S6 n  k& i' T
  24.                         }9 t% p9 m) [& J) G) J! L; F% G
  25.                     }
    ) l% D! ~( K- B0 U+ F- k5 Y4 L
  26.                     if(!$id){- v. V- G# n. L( P1 b
  27.                         $data['msg']='时间还没到,晚点再来吧。';. y- ?  [, z; Q) i; A
  28.                     }else{' z: ^( h2 r. p1 S/ l
  29.                         if($is_lingqu){# P* {; y, B6 d( J0 M$ I2 w0 U) k
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    " q# h; a; m% y# y' }
  31.                         }else{  R: W7 o" p! C6 F' W
  32.                             //锁表# {- j, f0 m$ Y
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');/ u, v  i1 U: c; ~' c
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();, I3 W8 m0 L) m' ]
  35.                             if($active > 0){% o5 F7 E$ ~3 O2 R3 ^# Y# W1 L
  36.                                 //开启事务
    ( C, Z( C- _! v5 W8 o; C$ ]
  37.                                 M()->execute('start transaction');
    9 @7 j8 @! v7 r) @1 F  F/ Q! a
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    " d" ]) g3 ^. |  s1 m% z
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));2 p( `) v' u- ^; t" @
  40.                                 $members_preferential    =    M('members_preferential');
    6 x6 ?: a# K7 G1 p
  41.                                 //对应投资金额,
    % f, w) Y8 b$ {# X
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));; d) e: ~4 i/ ]2 u# ]( L& s& A
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');' e: ?$ B. E; x6 l
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间! R! ?8 h1 }; R
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券; b: Z' I! @2 n6 r& F
  46.                                 if($save && $add && $add2){% e9 ?8 F$ i* _5 k+ l% d# o
  47.                                     //事务提交
      \5 F, {2 Q' _
  48.                                     M()->execute('commit');9 k3 X2 L( l: y. h
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';4 o5 A4 a! b5 W# _6 q: c8 J- ?& K
  50.                                 }else{- V! z) N' Z' y( P) V2 w) s) P
  51.                                     //回滚& t, S! E5 E/ u& I& A
  52.                                     M()->execute('rollback');% U- w# h0 w+ S7 z. o
  53.                                     $data['msg']='未知错误!';
    8 Q8 h* `5 ~' V$ }: @# F* I  B5 u( X! V
  54.                                 }2 y" R: _+ U4 S4 T6 N- o
  55.                             }else{  U/ Q* y9 Y: Y$ A, k. X, H$ R! O
  56.                                 $data['msg']='红包已领完,你来晚了!';
    5 I. c/ U* o& u
  57.                             }5 e# P$ r6 \; _6 B, R5 C
  58.                             M()->execute('UNLOCK TABLES');5 [+ Z/ z& G( i: }; I8 G
  59.                         }5 p, f& p7 O3 a! X# o$ S) v
  60.                     }
    ) g. x9 x  A, _
  61.                 }else{
      v8 C% Y) v' e# D8 A
  62.                     $data['msg']='非法操作!';% T+ K, q/ y$ ~* d0 _
  63.                 }3 p; s/ _; R4 E5 q- ^$ F
  64.             }else{
    * c& _; H- U# ]7 i5 d
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';) J* v9 v1 z; a, k0 Z* r: m5 _0 ~  p& H( J
  66.             }2 c9 ]; {+ I/ `0 E6 j( P2 @% n/ l
  67.         }  `7 t4 v; R0 {; ^3 q* {5 ?
  68.         exit(json_encode($data));2 A/ J( B: u2 l" U$ ~9 R4 k2 R
  69.     }
复制代码

6 |1 W; r- p* h9 t' U* ^# O) i: \0 u& ?& U: S* {
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-7 22:09 , Processed in 0.112679 second(s), 19 queries .

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