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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9873|回复: 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://请求的脚本
复制代码
4 w7 l9 R2 W' Z: Y" Y. M
Mysql中的锁语法:- X4 _1 u2 j# Q0 `
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】- B) \( k; T9 M" g8 ]
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表6 \1 |# A1 M* p: w- E/ z9 J1 v  l! l
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞4 M6 D% _9 t) }8 [- R7 g+ o
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
! h  Q( D# t5 L3 Y- v9 w文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。0 Z9 K% `+ {; w+ }5 z' n- h
测试时,有个文件就行,叫什么名无所谓
总结:* ?' c! ~0 l& B' T4 D
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
8 u0 Z5 y2 P# e& x5 @; P# O1 M1. 高并发下单时,减库存量时要加锁
* @* x+ ?6 E2 n2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    8 Q* G2 ^; n1 E9 Y& N+ ?
  2.     模拟秒杀活动-- 商品100件
    & b* B& B$ \/ l6 P# J' u
  3.     CREATE TABLE ta: f2 ?" u( q- T! l9 c' g# A
  4.     (
    . s  d* \+ N1 J. t+ b( i
  5.         id int comment '模拟100件活动商品的数量'' M, c3 D3 D5 I8 J3 [+ J! E
  6.     );
      l$ q+ `* z" Q
  7.     INSERT INTO ta VALUES(100);
    4 n1 n% C; T; G4 I% l; f2 a2 N
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件7 Z! f9 {9 o( s
  9.      */ 7 D; ~; O* b- ^& n+ o
  10.     + M: j5 k: L" y% H- R$ k  e
  11.     // 关闭错误报告  b* m- E! i' @1 R7 l, r
  12.      error_reporting(0);
    ! `$ O0 `- F- O) V/ T& S5 b: E
  13. 2 F6 ]: {" v; N, A5 a5 M+ L
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* P' A+ m8 c" D+ Y" i# J3 P
  15.     $dbuser = 'root';            // mysql用户名* B0 L2 _  p2 O% A- e
  16.     $dbpass = 'root';          // mysql用户名密码( z& ~( }6 ~" q7 f9 e0 Y) S% F0 q
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);6 D7 `& N& b  V
  18.     if(! $conn )
    + D: o: C4 d" f5 G2 j* I2 r
  19.     {
    5 S" _+ R+ F9 a& g. ^7 i, {" g
  20.         die('连接失败: ' . mysqli_error($conn));6 W; U0 W* c* R: l  A& K% X% s
  21.     }9 {* T, _2 [  [0 B1 J' S5 |
  22.     // 设置编码,防止中文乱码1 B/ _- F5 h6 ?" Q
  23.     mysqli_query($conn , "set names utf8");1 ~6 N$ P* {+ a' t
  24.     mysqli_select_db( $conn, 'temp' );   c8 R. J; W1 q8 ^
  25. 5 l2 }& u( J: ]7 d; |$ B
  26.     # mysql 锁
    ; r5 p' o) B! A& ^8 Y4 ?' K
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ( Z/ v) h- d6 a  L* @9 W+ Z
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); # S2 [! Q5 A( G) A+ \$ Z% ]7 K3 M
  29.     $id = mysqli_result($rs, 0, 0);
    ! {* X. k& f# H% z& _$ P
  30.     if($id > 0)
    4 J( v3 k3 E1 P4 F6 D$ v5 q
  31.     {
    ; [7 w0 v. W3 p. {6 H) @2 m) ?" E
  32.         --$id;
    $ S9 l& }4 ^6 `! U/ [, H6 v
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); / V4 p  y5 `8 J$ c- |
  34.     } 7 b" g- h: j% n) t" M% e) B
  35. 6 L: j1 H) Q: y4 m# D
  36.     # mysql 解锁 - d9 y: z% t4 I
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    0 x4 O: `* o2 |  K
  38.     //查询解锁后的id值
    6 K* X( I3 k0 [9 q% B  S
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    . J, f8 t- x& M6 `' p  {
  40.     // while($row = mysqli_fetch_assoc($res))( K- j' U0 f: T
  41.     // {& Y$ x. s1 ?' [' _
  42.     //     $id = $row['id'];8 |$ i! D& w; |( ]) l5 I# G
  43.     // }
    2 t7 a. W0 j0 I0 Z% q) g
  44.     // echo $id;
复制代码
$ r8 o6 w& T" q" C( X# S5 F4 _

, ]8 b( E0 y+ ~* e  k" \

  x% X- t9 M  h5 I
PHP文件锁示例:
  1. /*+ |" b1 t- J  }, b
  2.     模拟秒杀活动-- 商品100件
    , Q8 ?/ o0 ^7 i# j
  3.     CREATE TABLE ta
    " F- p7 |3 S2 N4 i% O% k( z! _
  4.     (
    3 [0 J- ^9 B" G  W7 H
  5.         id int comment '模拟100件活动商品的数量'
    . H7 m8 N7 E8 z' M( t. Q6 z" q
  6.     );
      w) {$ a! {) s0 R. ^
  7.     INSERT INTO ta VALUES(100);1 P' D8 W4 {& P: p4 {
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    , w( t0 ~5 v* a5 h
  9.      */
    - L- u+ m0 J" b; B7 g9 I% B' |
  10.     6 v, i* U/ E7 O0 k  Y# o9 f
  11.     // 关闭错误报告
    ( F5 m* G0 Y- z" Y; `8 v& F
  12.      error_reporting(0); 2 d$ ]; B- }# r9 a# p1 t  Q$ z( D

  13. ! C& y8 N) B6 N6 I; G( I
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    6 s" w6 `+ N% D
  15.     $dbuser = 'root';            // mysql用户名
    9 r0 _' R7 k1 f6 b7 U: f& V5 T
  16.     $dbpass = 'root';          // mysql用户名密码
    - t$ A4 F# U) r2 f
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    + V. G) B8 |7 J8 }- X
  18.     if(! $conn )* D- F" M4 |8 G- T: ]7 R+ R1 i
  19.     {; S$ ~5 ]! Z9 X0 [3 F# ^
  20.         die('连接失败: ' . mysqli_error($conn));1 s' [) }! z; `, T2 ^1 L
  21.     }
    2 ^6 t& f; u' t5 b3 W
  22.     // 设置编码,防止中文乱码
    8 G/ k% t7 p& [7 Y! r- R$ z
  23.     mysqli_query($conn , "set names utf8");1 _6 X' g  |( n- m1 l: c4 ]/ \
  24.     mysqli_select_db( $conn, 'temp' );
    5 r1 `+ d- W: e. o. C# P) c2 j
  25. / |" ]6 U; ~5 D/ @# j
  26.     # php中的文件锁 " h: S7 F5 v& f. S, e7 |) V7 w! |
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 - y: o6 `) I) W# r- G7 p
  28.     flock($fp, LOCK_EX);// 排他锁
    7 d1 ~- S5 s5 q# |

  29. 0 V! e6 f3 E( A, R5 d* s: G  S- U
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 1 `0 Y, c- o8 O* Q. ], }0 f
  31.     while($row = mysqli_fetch_assoc($retval))! S1 f, J4 |0 `# I# }) \
  32.     {
    " w4 M8 j7 \' n) O4 L9 q9 r
  33.         $id =  $row['id'];
    " Y: P% q' u% g) N0 b
  34.     }
    8 C1 R# J" N# n. U/ x- @
  35.     8 C8 q3 V3 V; F2 k6 @6 S# M
  36.     if($id > 0) + Z/ i( X5 T. A8 H
  37.     { 5 D  h- W$ O* o% c: p. |
  38.         --$id;
    0 e' t9 D) Y& b1 k! S) n
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); , r5 F4 u% I/ Z  Y) L2 b. @
  40.     } 2 Q( W$ d+ g% ~! u. X0 {6 d; e
  41.     # php的文件锁,释放锁
    . I" p( ]) D% n' A- c, b: i
  42.     flock($fp, LOCK_UN);
    - W# s, |0 E# x
  43.     fclose($fp);7 B* K5 h8 u* B4 P# D' d% F

  44.   @1 y* A2 {/ Q( O, ~3 v. v
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    4 l. C$ |* w  |0 h& A1 ]
  46.     // while($row = mysqli_fetch_assoc($res))
    8 f; X' `  X# n5 x
  47.     // {
    6 |  a1 d+ W5 `( G3 v
  48.     //     $id = $row['id'];
    0 ?( n. \: q/ c8 ]7 H4 y
  49.     // }) D% g6 d0 C  Q9 v3 G
  50.     // echo $id;
复制代码

- K3 D& B: L# J* y' E
7 {+ @6 H5 x& W
抢券活动实例:
  1. public function envelopeSnatching(){( T' ?* s/ a) G/ U
  2.         $lingqu = $_POST['type'];
    ! u  R" p1 R8 i0 L
  3.         $uid=session('u_id');//用户id
      B, D4 c; T3 l# L5 v
  4.         if(!$uid){: X( G. D$ K8 B5 O9 ^2 Q% I* G
  5.             $data['msg']='您没登录,请先登录!';
    1 m$ [' s, e/ c3 x' M
  6.         }else if(date('Y-m-d') != '2017-12-12'){& ^  [1 Z9 ^6 S- c
  7.             $data['msg']='不在活动时间内!';
    6 ]% ?2 \8 W$ ~8 Z1 q- U+ y/ B
  8.         }else{
    1 _  l- Q- }: ]+ {7 T8 X
  9.             $hours=date('H');//当前小时数0 o! H. n0 w7 |/ X8 K$ l  [& L
  10.             if($hours > '09' || $hours > '17'){
    # y/ c8 ]1 M6 V4 e* o* n
  11. 7 a. E% S: A" q# d" d  e+ J
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    8 S. w3 L: b. k# n3 w- g
  13.                     if($lingqu == 1){7 ~1 S1 k6 u0 a5 H4 [+ f2 @
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    ) o- U1 g7 l' B+ P, r! J
  15.                         if($hours > '09'){
    " y/ P( T' w. b4 }% U" }( W
  16.                             $num=mt_rand(25,28);//优惠券金额6 Z+ ], }+ R' Q0 l
  17.                             $id=1;
    ! N1 a+ o4 _6 b/ K' I
  18.                         }- Y* Y2 g! I% C. ]3 \2 P2 C2 q1 \  M
  19.                     }else if($lingqu == 2){
    9 j' Q& i. N$ B
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();& s% |1 E2 C& {( c& Q
  21.                         if($hours > '17'){
    & c3 o8 S- D% s% q6 J6 f
  22.                             $num=mt_rand(50,55);//优惠券金额- H; |1 P8 g; Z- t5 Z( w
  23.                             $id=2;: r* I7 r8 w; R, m1 j
  24.                         }
    " U( G! r0 ?6 d. h+ `$ a
  25.                     }/ O) [) H; {# Q8 _4 x
  26.                     if(!$id){. `1 z- U# |2 I- ]
  27.                         $data['msg']='时间还没到,晚点再来吧。';6 C$ {6 g( ~2 \% U7 M
  28.                     }else{
    : {4 t9 b4 O) C2 b- J& O2 ?
  29.                         if($is_lingqu){% o0 y4 Q6 V" E3 ?, S+ o
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    3 e) J& A0 o# m$ G3 m1 \
  31.                         }else{6 d7 s( }  z, B8 f# a) P8 E7 f
  32.                             //锁表
    , K! I9 B7 v# G
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');/ X, e3 D, z! J! u6 i( K6 n: {7 I
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();; q( Z( Q5 r' X" {3 v3 |
  35.                             if($active > 0){) g3 [8 e8 a8 k1 F+ D9 u
  36.                                 //开启事务
    0 p  y3 q. n0 P% e5 E: I" I2 h
  37.                                 M()->execute('start transaction');
    ' r. k: Q. r, X" U- o& |9 h
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    ' u: }; ^; w. _) h4 O
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));* c7 p. ~% }! b" A6 ~* x1 X
  40.                                 $members_preferential    =    M('members_preferential');
    % B& u7 B7 s8 ~9 K# N" y) g  \4 P! F
  41.                                 //对应投资金额,/ V9 t5 y& B0 W* X, {" Z* p& d
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));  m& W/ i* N$ R& K
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');" ?& _9 t4 @0 c, m- Y: v
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    - k# ~/ m( `) i: U# ?# m. y# |
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    1 _9 t" T$ K, q8 E! k' e
  46.                                 if($save && $add && $add2){
    2 A& Z! l; A/ F4 U
  47.                                     //事务提交& C  `2 C9 l( \
  48.                                     M()->execute('commit');
    7 U0 o& c1 I- @
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    6 g( f5 p0 T, p
  50.                                 }else{% e6 S- ~6 t3 ^, Q  t8 S$ N4 [5 q. }
  51.                                     //回滚
    : G3 J3 B5 `6 ~0 g% i
  52.                                     M()->execute('rollback');
    - j2 e, d( U, K
  53.                                     $data['msg']='未知错误!';
    2 W8 d# G  R, ^! u2 l2 C
  54.                                 }
      ~" n6 Q# G8 s9 \3 c
  55.                             }else{
    8 ^$ k) Q* l$ @1 u& o2 }* }. x& I5 G
  56.                                 $data['msg']='红包已领完,你来晚了!';
    ' f' f9 Z- ^, b" x  H. ?/ U4 Q
  57.                             }
    8 i, y" q: K: K7 j! |& D
  58.                             M()->execute('UNLOCK TABLES');
    4 P; g/ p( U$ i2 l
  59.                         }
    9 L& Q5 z$ s4 b  e: t
  60.                     }
    4 U# ?& `6 }, T  ]
  61.                 }else{5 I) i( N- X. c
  62.                     $data['msg']='非法操作!';
    ( _$ N# K2 e. @# V0 q
  63.                 }4 g) b) m; O$ R- e  @
  64.             }else{# v7 w7 M) W1 R$ T+ f( {0 ~+ z
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';& f; K/ }+ W; |3 D  j1 a
  66.             }' q. L; V! f3 r0 o3 J8 `
  67.         }# H5 P6 L1 \: k% s, ^6 U! ?+ F
  68.         exit(json_encode($data));
    / i* P1 Z% o4 g0 c/ M
  69.     }
复制代码
$ S0 [- t( b/ S, w$ V, S: H! O

( L) N& y4 H/ @# ?0 \
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 03:12 , Processed in 0.056662 second(s), 19 queries .

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