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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 4018|回复: 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://请求的脚本
复制代码

6 h, U5 b! q+ Q3 M' {3 J5 q; f
Mysql中的锁语法:- }) j) O4 T3 P0 q
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
; N' V& t5 i1 vUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表$ Y! S& P* N  T" m& w
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
4 a5 E5 n0 p9 S6 S' ^: [# N注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
8 ]/ n/ `2 a" C! W6 @文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。1 f9 o# J% `" t( X. G. ?$ L. e% c
测试时,有个文件就行,叫什么名无所谓
总结:$ Q7 j' D% o  u1 ]+ _8 x
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
: I0 X3 R% P4 g* E( G1. 高并发下单时,减库存量时要加锁
% f% X# {8 V4 @+ r5 F2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    4 G, C/ W" o2 k( z, ]& ^
  2.     模拟秒杀活动-- 商品100件' v, x7 F- ^8 q( _  H# \
  3.     CREATE TABLE ta: t* D/ j5 d" S) q  z+ }: r
  4.     (
    . l# d; d1 d' l( W' x
  5.         id int comment '模拟100件活动商品的数量'. ]3 U1 g/ @1 Q7 z
  6.     );
    8 t6 E8 n* _& I, ]. Y1 U* ~! s
  7.     INSERT INTO ta VALUES(100);
    6 K% G5 _% ]* o5 V  f5 k
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件' {2 ?, x$ Q  T+ X, R) n
  9.      */ ; w3 P$ G' n3 o+ f
  10.    
    " k1 \- k0 W$ x+ Q- ?; l
  11.     // 关闭错误报告
    $ c! V8 z- w  x' D+ p, h. i
  12.      error_reporting(0); ( e: r4 c3 N7 e5 [
  13. , k) W) ~) d3 `* z8 E
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    % t2 k+ D+ g5 ?' H4 @8 p! ]3 ]1 G9 ]
  15.     $dbuser = 'root';            // mysql用户名
    ; S- L% T2 i% T7 ~) @. `
  16.     $dbpass = 'root';          // mysql用户名密码7 d0 Y, h/ W4 ?" \2 e( i
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    . y. s/ Z7 I0 M% u0 [2 ?
  18.     if(! $conn ), D; p* x4 ], w. M1 f! U. t- y
  19.     {
    ! {( L* X. p& b$ J- x" A1 R
  20.         die('连接失败: ' . mysqli_error($conn));% _2 T  V: l2 r
  21.     }: E8 Z- k& ]' {
  22.     // 设置编码,防止中文乱码6 C( ]0 S, O- O- R0 O" m/ j+ N& p% P
  23.     mysqli_query($conn , "set names utf8");
    ) n+ Z0 G4 c0 @$ B. ]
  24.     mysqli_select_db( $conn, 'temp' ); . V/ w2 S; Q# k
  25. ' {7 R) A1 z/ T, X
  26.     # mysql 锁 : D+ l% E, L/ v8 O% C3 q* i3 R
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    0 R4 l5 s: i3 ^+ A4 V2 y0 X
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 3 [" {  u& L1 \* u! E- j
  29.     $id = mysqli_result($rs, 0, 0);
    ! T' P' _6 T  n$ |' B1 C
  30.     if($id > 0)
    " U+ X5 Y% K# ?% G. c& m
  31.     {
    . s* K$ n. Q+ F/ D' t
  32.         --$id;
    1 T8 D3 X) z% r% }" x; p- V
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    0 ]2 @" l% }. I2 p$ x
  34.     } 1 l" c- w% k9 i0 G
  35. " G2 T: {8 q) |7 `2 C
  36.     # mysql 解锁 6 Q. V7 C1 T6 g
  37.     mysqli_query($conn , 'UNLOCK TABLES');- d* h/ D$ p3 f! N9 j
  38.     //查询解锁后的id值' X' l: |( z; N/ b: V1 M
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    5 z6 x' N* [3 g" J
  40.     // while($row = mysqli_fetch_assoc($res))& o0 R9 `! Q/ ^- }  L
  41.     // {2 z$ y) G4 `9 r! y1 U
  42.     //     $id = $row['id'];3 P+ x. J; Z6 J0 u8 W
  43.     // }
    " P9 y7 w8 `; d( v+ N
  44.     // echo $id;
复制代码
+ f8 K% Q$ `( |( I" Y

" v% s0 c+ w8 L( t6 g
: K: Z! ?( }- \/ k  e  E( c5 S0 g
PHP文件锁示例:
  1. /*
    / G2 g1 ~7 }  m' K6 V4 ~6 \: m
  2.     模拟秒杀活动-- 商品100件
    ( e! G/ D5 K& }& w* z. j2 ^- Z! h
  3.     CREATE TABLE ta
    * v- a9 G0 m1 s) A
  4.     (  ^' F6 ~4 c3 [* k$ B' R
  5.         id int comment '模拟100件活动商品的数量'3 j' {3 y! R6 i* T9 F# Y
  6.     );
    % i. t% }( b6 }, r2 d
  7.     INSERT INTO ta VALUES(100);
    2 E/ x. W. t$ R: t; x% ^2 M
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件5 ^5 x. V8 T5 S: ^% I9 _# B
  9.      */
    , m0 y' Z0 ]& G) [' D3 z
  10.     ; K! y% X2 m$ ~
  11.     // 关闭错误报告
    ) G5 {! \9 }  A; J, C4 A! a0 g! c
  12.      error_reporting(0);
    ; P: N9 j6 M2 G# S7 p: a

  13. . i0 I1 }+ ]: `
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    / Q+ K( b7 @; J0 Y: J! ~) l) {
  15.     $dbuser = 'root';            // mysql用户名9 q1 s5 S3 S; e2 {% t' d( u
  16.     $dbpass = 'root';          // mysql用户名密码
    8 K# M- R4 x% I
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);0 m4 b, G7 y8 X/ u5 m5 j0 h4 w
  18.     if(! $conn )
    % k) n& L/ _4 o/ C: t( C8 q' K9 x
  19.     {
    ' a; H+ D3 J. u1 n" B/ w
  20.         die('连接失败: ' . mysqli_error($conn));1 a6 C! z* \: |1 T0 p8 m5 @6 r4 p
  21.     }, t5 k  g+ H) \: x2 A  J
  22.     // 设置编码,防止中文乱码! L7 q/ P1 O4 I2 n2 `
  23.     mysqli_query($conn , "set names utf8");
    % \- w! z6 R% ~
  24.     mysqli_select_db( $conn, 'temp' );
    + C; \" m. ~. c" n. }/ h
  25. % b1 D. \1 [+ Y. y& u4 K! T6 e
  26.     # php中的文件锁 $ y- K. V7 r3 g
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    ( ^8 l8 }) x; w; U% E
  28.     flock($fp, LOCK_EX);// 排他锁 ( P2 [% K. `1 s. b( s
  29. 9 _( q. I- D- r8 W6 F9 k
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    , P+ t1 L! i6 R! n8 h
  31.     while($row = mysqli_fetch_assoc($retval))
    * t  T1 f3 H1 G- C1 ^
  32.     {
    8 A; H( q$ E9 j0 _7 Q; Y
  33.         $id =  $row['id'];' ]- K+ F* W- |4 m4 s# ?: s
  34.     }
    ( L9 x7 |# t" ^4 w
  35.    
    5 C0 ]/ b( z7 @5 F
  36.     if($id > 0) + |) b" k4 f* k4 h
  37.     { + L8 x) z2 n$ P* t; k! D
  38.         --$id; 5 a, K& ^( V: I
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    : n$ Y; o9 y+ w% A) O
  40.     } , ]  s% r1 {: h9 ?0 ^. n' K
  41.     # php的文件锁,释放锁 % P. ~/ D  @/ |5 w! M- W
  42.     flock($fp, LOCK_UN);
    0 `3 `; ?& `* L  A5 V
  43.     fclose($fp);
    $ ]) F& z( c% {

  44. 3 s8 A: V: C! `  g
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');. ^: m4 `& j: r: R+ P2 u9 ], v
  46.     // while($row = mysqli_fetch_assoc($res))
    : b: \5 D1 P6 o6 v1 P* G
  47.     // {
    6 {1 I" U7 p; e4 }
  48.     //     $id = $row['id'];* w: v7 \+ ]5 z+ N) b3 n6 _
  49.     // }( W4 u7 o4 x% C5 q
  50.     // echo $id;
复制代码
4 x, m2 f0 n3 |# \8 W( G7 Z4 Q; q
1 {; W% {; ?2 I
抢券活动实例:
  1. public function envelopeSnatching(){  Z$ o2 c" b0 g1 Y6 V% Q& u7 q
  2.         $lingqu = $_POST['type'];  ?5 d  U" p+ q* H, U" |
  3.         $uid=session('u_id');//用户id
    3 k0 |9 t  a- K! C2 K8 I& J
  4.         if(!$uid){) G5 U8 k6 e1 Z& Z3 A' q& d
  5.             $data['msg']='您没登录,请先登录!';0 @* k* `' g/ H+ J* e
  6.         }else if(date('Y-m-d') != '2017-12-12'){4 B2 ?. Y/ E4 o0 V) C
  7.             $data['msg']='不在活动时间内!';
    6 u  [; {% X& G
  8.         }else{- G3 f. |( b6 B" t# a5 K
  9.             $hours=date('H');//当前小时数
    8 a$ r; J" a* F- M/ l
  10.             if($hours > '09' || $hours > '17'){6 m8 L/ D2 b' k9 W: q( z' y, G
  11.   c8 n: L2 R5 T  p2 e4 q
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的' J* B9 s- g: ]* d0 Q; ]- c
  13.                     if($lingqu == 1){
    4 B* u$ t* H6 @$ o, i# P2 g% C1 a' b
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过# y* N+ [: ~3 r( @, f! t
  15.                         if($hours > '09'){+ o' h* y% M% ?4 s7 r3 H; b
  16.                             $num=mt_rand(25,28);//优惠券金额
    9 M) Q) e5 e- p( y
  17.                             $id=1;
    ; a" Q5 m' a- S1 X, @5 Y0 b
  18.                         }6 Y4 S* d( C' X1 d- c8 F+ w8 F6 B
  19.                     }else if($lingqu == 2){' N# n% E4 @4 ^4 E; i( E8 I6 G
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    % w" a( D4 q6 f! C* c2 _
  21.                         if($hours > '17'){6 g' ^5 W/ F6 g' H  r9 D
  22.                             $num=mt_rand(50,55);//优惠券金额
    ) A2 N( X, Q0 p4 D2 ^8 N. Y7 C, ~
  23.                             $id=2;
    ; ?/ |3 X( P% ?8 C
  24.                         }8 y+ e" I2 j: ~  I7 u2 N& ]
  25.                     }/ T- r  q3 m1 L- K. ]* E! T
  26.                     if(!$id){% J9 Y$ F+ P  S( o
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    / @7 H' V$ _6 _
  28.                     }else{
    # z' `  W+ m, n
  29.                         if($is_lingqu){
    - M( ~! J# q3 f1 z# P
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
      M, X/ B) i, X6 o  y
  31.                         }else{9 X0 I7 S% w# A) r
  32.                             //锁表
    9 E/ K: U  [% c( t/ G& a
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    7 S: [% r: \' _
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    $ u% y2 R# _6 U; V) i
  35.                             if($active > 0){, }! ^/ J7 X- J& R' V
  36.                                 //开启事务
    . m% q2 W6 A+ ?0 u- W) G
  37.                                 M()->execute('start transaction');! @1 |/ ?7 L  z# W' l- b
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));$ K0 r+ w# u+ L2 x
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    2 |1 K" Z- `, _7 A5 B8 Y3 z
  40.                                 $members_preferential    =    M('members_preferential');
    9 s1 U' s! j. M* u+ z$ M; j3 f  R! ^' s3 ~
  41.                                 //对应投资金额,
    - Y  ~# H- k" Y, J
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    $ D8 p# n3 F$ ^: P6 X, y/ y/ q- w7 a% B
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');, d& C! T) h8 @, ?
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间: S( x# q) x/ V% N# u
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    8 G; c  X7 M8 ^3 @
  46.                                 if($save && $add && $add2){
    4 D$ Q4 v. ?+ O* y0 C7 {! E1 f
  47.                                     //事务提交
    7 x5 O/ x% G; k1 o2 M5 K
  48.                                     M()->execute('commit');
      D( F* l( o& N: q5 b; R
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';+ N1 w6 F' {8 B) f, A& J3 F
  50.                                 }else{( A( R5 I2 w* ~+ i9 f; t6 D! J
  51.                                     //回滚2 Q; C' J" g8 e5 M' e8 `; w% X
  52.                                     M()->execute('rollback');9 @' [# h/ ^- |" w  f2 V8 Q2 M( p
  53.                                     $data['msg']='未知错误!';
    * t( r9 x9 y! [; i- u4 G; R
  54.                                 }
    1 G, ~; J, I. z9 P* s
  55.                             }else{$ N9 \0 B6 _5 W1 ~* v0 [( O
  56.                                 $data['msg']='红包已领完,你来晚了!';* c) ]8 D/ H" p0 {
  57.                             }
    . @5 y- ~, K; S+ F, L. G; T. \& ~
  58.                             M()->execute('UNLOCK TABLES');
    8 L2 X, J5 I, a4 q
  59.                         }
      w/ \0 A4 e; A; S( v: T
  60.                     }
    : ?' \+ W" y! J9 J; ]) `
  61.                 }else{  {! j) h9 n$ A& H- e5 d+ v- @
  62.                     $data['msg']='非法操作!';! f. z" I9 w* d8 {
  63.                 }6 \6 K+ S- o0 @- B  Y" |
  64.             }else{' u0 ~0 v+ J4 U2 ~) J9 ^1 |
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';" s2 u  P& B+ c  o, ?' p+ |  M
  66.             }
    8 J; a6 O# X( _1 b3 u6 G
  67.         }3 C! E: L% x4 t; u1 x4 I
  68.         exit(json_encode($data));
    ; r/ s3 r- d! y! q% h+ ^  R
  69.     }
复制代码

% a: b' x/ ]9 H) f: D( ]9 U" Y& H# L( s+ }' _
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-20 04:09 , Processed in 0.141709 second(s), 19 queries .

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