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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

8 Q8 O$ ^5 H: s+ }8 u- M  Q: e; l
Mysql中的锁语法:4 h1 C' b8 o% c1 N, m0 ^6 i
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
0 B9 U: g! C& B7 J% z) [) CUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表5 \  t; X! E  ~0 q
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞) C% }+ L3 j3 _: k3 M$ G5 i
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
) P  G$ h4 d: v. D. S文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。% v$ I1 {# @8 t/ d
测试时,有个文件就行,叫什么名无所谓
总结:6 v* N4 r5 j1 r
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:' u0 [! i1 G* o( \+ l
1. 高并发下单时,减库存量时要加锁! Q* v! t' P: R2 V
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    / r# P0 j% L0 r6 W$ x
  2.     模拟秒杀活动-- 商品100件
    # M7 A! n/ C% S4 R. }5 |8 x4 P
  3.     CREATE TABLE ta& V$ G7 O0 i7 y% {0 j: z" k
  4.     (
    1 m: E( ~' |# V; Z6 e+ I
  5.         id int comment '模拟100件活动商品的数量'% b5 i* R2 W# N0 _% Q3 \1 m/ O9 |
  6.     );# }3 K4 Q! h, M' K0 h6 {
  7.     INSERT INTO ta VALUES(100);# b7 r0 L7 j0 z7 Z5 Q5 D
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件( q/ l; M, s  x7 ]
  9.      */ ; q6 ]' r! q; s$ J) `! U# E- x
  10.     / K( B" c$ O' ?" Z( R; P5 c
  11.     // 关闭错误报告5 o& _8 v8 q; i- s) o
  12.      error_reporting(0);
    ; ?+ l& e" x8 m% p; D

  13. * g; z2 A) v  O7 b
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址& x7 }; f: g" X# {
  15.     $dbuser = 'root';            // mysql用户名( }4 Y0 r/ [' R5 \9 i
  16.     $dbpass = 'root';          // mysql用户名密码8 r! O$ e' n8 ~4 s: Q' ?8 a
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);3 _5 L) j1 X8 u" o' K& F
  18.     if(! $conn )
    ) i8 v$ m: ?$ L$ J1 `5 D
  19.     {
    6 i3 f" e! w! ^! l
  20.         die('连接失败: ' . mysqli_error($conn));* M9 I3 c7 a: m. v# t
  21.     }
    + s9 b4 ]( Y5 `" J: }8 o. j% W
  22.     // 设置编码,防止中文乱码
    " Q5 ?( U/ b% T5 G0 T; {
  23.     mysqli_query($conn , "set names utf8");
    7 `# ?1 ^7 o+ L6 v7 Q9 V- P. e
  24.     mysqli_select_db( $conn, 'temp' );
    ) A+ r1 l/ a4 y2 S, b# a8 ]* Y; M; Q

  25. " w# _  ]6 B- e& ]' a
  26.     # mysql 锁
    $ `; v) i- w) ~3 C
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 & Y, R3 ^0 t% k5 m
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); ( u+ Z' G- K7 r5 T
  29.     $id = mysqli_result($rs, 0, 0);
    0 T6 S2 U2 V2 _% o. ~+ l4 j
  30.     if($id > 0)
    ' v0 t, z; r# ^. R9 R3 s
  31.     {
    : I4 ]! H/ j2 L
  32.         --$id;
    : c1 p+ X( W) x& H( f/ r  S3 F) m
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 0 K9 k) E6 \( @5 m: b9 E/ c# a
  34.     }
    . U  N: G+ e8 w; T# K

  35. ) l0 X" d4 ]6 W6 V- e! b
  36.     # mysql 解锁
    # c, A# d- b) C8 Y4 |3 ~0 k
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    # R+ Z/ x0 U+ I+ {" z: P
  38.     //查询解锁后的id值' ]" x) @6 J/ D" w$ `' c7 P  P8 I
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    3 ]' x' L3 F3 W4 k4 E9 w" Y+ e; d
  40.     // while($row = mysqli_fetch_assoc($res))
    " {. F$ p5 t& J8 O/ Z
  41.     // {/ [7 x% w& K4 U
  42.     //     $id = $row['id'];
    ) P8 c; h2 t- A7 F
  43.     // }
    " p( o& Z+ q. ]2 S) [# J
  44.     // echo $id;
复制代码
( m% T  w+ D2 n! Y- B% n8 u' _3 ?2 U
0 n- o$ x$ d) {' E& t! v
3 c1 x$ @. F" O  h8 _# m
PHP文件锁示例:
  1. /*
    " F8 X' k! s1 y+ g
  2.     模拟秒杀活动-- 商品100件1 ]. h2 n$ q6 n, |: j/ O
  3.     CREATE TABLE ta
    % b' z7 s. L3 I! B, M. N
  4.     (
    $ q% V$ h6 i9 n9 S" u
  5.         id int comment '模拟100件活动商品的数量'. \9 F; P- D+ d
  6.     );
    : Q. v  g$ Y; P( g! I/ j. Y
  7.     INSERT INTO ta VALUES(100);
    " H- I1 {; R$ O# P8 \9 R
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    7 W1 F0 c" V! j) c! b& K
  9.      */   \  L4 D+ V2 H7 d8 {
  10.     " D5 S! O# C% {: K$ ?; u9 M: i3 R% S
  11.     // 关闭错误报告
    ' ^+ `9 S7 |, `; N% A; ^2 B2 L0 e
  12.      error_reporting(0); $ T/ p; p( v+ p" p0 _

  13. 0 W3 M, b4 r/ g: v0 f, u
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( M. t, L( C2 M. O# L5 t
  15.     $dbuser = 'root';            // mysql用户名" B/ B/ q- j" Y$ `
  16.     $dbpass = 'root';          // mysql用户名密码
    , m5 v, C" c8 @" |. N
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);2 s% N: N% G1 v" O
  18.     if(! $conn )
    0 c" E/ S" `' X1 J: q4 D9 O" e, V
  19.     {
    $ C8 N  h( v: r4 S1 i* E
  20.         die('连接失败: ' . mysqli_error($conn));3 V+ k/ E( Y/ k+ r& y" V
  21.     }
    $ Y- v6 c, ?, x( n6 B+ P
  22.     // 设置编码,防止中文乱码
    ! o3 u8 o7 t) S' p. Y) d) g7 h" ?
  23.     mysqli_query($conn , "set names utf8");3 p, R, F$ v3 |3 ]/ |) b- t4 Q9 z
  24.     mysqli_select_db( $conn, 'temp' ); - @- y( `+ d+ S. d" g

  25. * u2 p, k" a; q0 a0 ^' h, T" R9 O
  26.     # php中的文件锁
    3 y+ H' a- C/ I7 P
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 9 e5 x4 F' F3 U$ w2 \
  28.     flock($fp, LOCK_EX);// 排他锁 ! |! A: K- S4 X8 n* V. e  }$ [1 _' R

  29. . v+ M  Y. q; u
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    - m* s7 m$ D# T. D
  31.     while($row = mysqli_fetch_assoc($retval))
    0 a& ?4 D* a' Y9 J3 T+ r
  32.     {; ?8 E  J9 D0 a/ \( Y$ m
  33.         $id =  $row['id'];
    / V$ B5 _+ l# q9 x9 {, B+ P
  34.     }
    % H/ s6 C+ B) z" V2 m
  35.    
      c& f$ k0 s& q8 ?
  36.     if($id > 0)
    1 r+ s0 ]8 A) ]$ Z3 m6 F9 j: |
  37.     {
    * j7 F, d/ b$ ~  i. X/ ?* A
  38.         --$id; 0 j$ x& t$ m. ~7 m3 [" k1 q
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    + k) [6 }% N; U
  40.     }
    % u& f) J7 [. g! I- b# r
  41.     # php的文件锁,释放锁
    # S; V9 c( N' Z. [, e* N' _
  42.     flock($fp, LOCK_UN);
    5 D: H: o/ U8 z! P3 v: p  g9 p
  43.     fclose($fp);
    8 I9 v$ q. a- \

  44.   k% L8 C6 I* N
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    5 ~, V1 `& r" G9 S3 b' q
  46.     // while($row = mysqli_fetch_assoc($res))* E" @8 G2 M" H* l
  47.     // {, \* w1 J0 o: d, c( f
  48.     //     $id = $row['id'];, C% A3 ?  g( E2 d1 N
  49.     // }: ^% Z+ H6 W! R5 g7 |
  50.     // echo $id;
复制代码
  G8 E; _' Z( r+ k/ z, F

( w% [; N$ [/ Q- R
抢券活动实例:
  1. public function envelopeSnatching(){
    3 P; I1 f" e0 O  u, w
  2.         $lingqu = $_POST['type'];
    ! H  g8 R( D( u6 T& Z
  3.         $uid=session('u_id');//用户id
    ; U& N6 a; ?6 v/ K' Z9 L( Q
  4.         if(!$uid){
    3 |6 ?# \  L* Y9 a* j- d2 J
  5.             $data['msg']='您没登录,请先登录!';& H% X& U; `( b
  6.         }else if(date('Y-m-d') != '2017-12-12'){6 s6 f8 ^% {  M4 U  b# R
  7.             $data['msg']='不在活动时间内!';
    8 {1 f& P. X/ t4 Z6 p0 i
  8.         }else{' s! l9 O' d4 [4 r
  9.             $hours=date('H');//当前小时数
    5 X+ w2 }8 l# r+ S  ~9 G8 b
  10.             if($hours > '09' || $hours > '17'){9 d; ]7 U3 G" ?2 C( |) m6 l

  11. 0 P0 T" ]- d$ [/ L
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    , O: I" a; w3 I6 w" _
  13.                     if($lingqu == 1){3 @/ r% Q3 ?8 M/ }
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过/ T$ a% r1 C, d8 x5 Y
  15.                         if($hours > '09'){
    & |6 u- I, _$ K1 r& B: w
  16.                             $num=mt_rand(25,28);//优惠券金额
    & I3 [" H* C2 h( |
  17.                             $id=1;
      Y$ L4 {3 o+ _/ c8 ^7 ?
  18.                         }
    5 ?4 K# s: F6 y
  19.                     }else if($lingqu == 2){# I" t' L! U6 \/ q4 z8 V8 p
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    6 W% ], \+ i& t3 x, P. A9 _/ k
  21.                         if($hours > '17'){5 A' U: J4 D0 S( Q: h3 [  J: e
  22.                             $num=mt_rand(50,55);//优惠券金额
    : t" T5 }( r7 D$ ~  Y
  23.                             $id=2;
    - [# q1 @, D' j
  24.                         }
    ; c8 ?5 s1 r: R4 g! w
  25.                     }
    / q$ j* ]. L! I
  26.                     if(!$id){3 `1 ^  w- ^2 y( r% q" U; F" Z- \
  27.                         $data['msg']='时间还没到,晚点再来吧。';1 |  i. L) [7 r6 G
  28.                     }else{& R& m7 G. k& u6 F1 C% S2 x
  29.                         if($is_lingqu){% |6 g6 h# g# c( V' k
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    " }( ~# Q, f' p9 y) U1 R
  31.                         }else{$ \; x3 E# ^4 o
  32.                             //锁表' ?9 D- K" i5 r, H, B# L& l
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');. X2 e- y, j& S! h- k
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();/ r6 a1 o! R; j" x( p7 I
  35.                             if($active > 0){
    " ~# e2 q" p% k# M: `* G* l
  36.                                 //开启事务8 K# O1 G+ R9 t) k
  37.                                 M()->execute('start transaction');
    $ L1 u: I6 ]" a. ]
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    - ?; Z5 H# i0 j
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
      O& l' A5 P5 [! z7 K. I
  40.                                 $members_preferential    =    M('members_preferential');
    # I# i7 Q, S* E  o8 l" S& K0 Z
  41.                                 //对应投资金额,
    ! t% @/ E) {4 |0 F& C% e' e
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));* ]% c  C4 d2 ~: m, I; Y  v
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    8 ?- B7 \- Y( K  P% |
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间! h% ]; c' R: W% y
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
      O+ r& o1 T+ z: @. W. b
  46.                                 if($save && $add && $add2){
    ! V% |$ ?0 L- g) i( c$ J9 I
  47.                                     //事务提交  y5 O* G$ Z- }6 B5 Y. |: V
  48.                                     M()->execute('commit');# u3 G; ~0 `# S0 p
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    ; E& g3 e& \! A' y  t; h$ c
  50.                                 }else{
    ; D9 V( g" K. T# s/ e
  51.                                     //回滚
    , T; p/ D) d- w* P  `1 q
  52.                                     M()->execute('rollback');
    * W4 J$ R' t  a& q
  53.                                     $data['msg']='未知错误!';
    " s* c6 T$ [5 B: ~3 _8 k
  54.                                 }6 _3 D3 `, F8 a7 e( ]# w
  55.                             }else{- Q' C) `  O6 U5 Y5 W. x1 g
  56.                                 $data['msg']='红包已领完,你来晚了!';& v% Z5 n( e& z# j0 t2 l
  57.                             }
    4 D/ W* s4 t7 R8 b
  58.                             M()->execute('UNLOCK TABLES');* o& ~- ]; d" \  p, k4 r
  59.                         }
    % s2 P: v8 m9 B9 i
  60.                     }
    1 b3 Z- ^- n% x& _" A/ ]
  61.                 }else{/ j: Z- @6 g- W: F
  62.                     $data['msg']='非法操作!';
      m# `9 |4 i. ]- b; j' o7 k
  63.                 }; j3 G% q& \2 Z0 ~
  64.             }else{# ^, ?* e, b& `% d3 q% k
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';* n: j, v8 z! V  r. d
  66.             }1 E* j) ~3 n) s0 w5 c; A" n4 m0 |% p
  67.         }
    0 l$ M) M+ V! g  g9 u8 x0 p
  68.         exit(json_encode($data));
    5 A% c) e0 n$ u" W2 _& _
  69.     }
复制代码

  K* w$ D/ P- O9 m1 w
; G& `: h7 B# c
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 23:05 , Processed in 0.128552 second(s), 20 queries .

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