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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 4898|回复: 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://请求的脚本
复制代码
+ ?  M0 G: b5 D1 K' t6 O+ \
Mysql中的锁语法:5 z" J6 i; [3 ^* o+ j# ~! _' p
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】: C2 ~- h1 y9 |  ]# F7 s/ Q
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
2 X% C. `' T# i8 \Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞6 E8 U  b: _) c" X8 ~% a
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :- p7 t! ?( A% X- L4 U, p' P5 P
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。* Y# b! `+ t" r, b
测试时,有个文件就行,叫什么名无所谓
总结:2 _# D% M* z% n) c# t' k
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:4 q) x4 d+ M6 Z7 Z1 A9 t" ?# B
1. 高并发下单时,减库存量时要加锁
4 o5 S2 t/ O! d" S1 ]( k, h4 K2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    $ j) p8 U7 |, N
  2.     模拟秒杀活动-- 商品100件
    8 U. _, j, L+ A- O
  3.     CREATE TABLE ta
    9 J, L) h( M# y0 Q- t, K  E7 b
  4.     (6 B4 ~* A4 J2 q* G
  5.         id int comment '模拟100件活动商品的数量'
      W5 I% @0 N. g  F1 p
  6.     );
    : t$ ]& ^3 e# v% e  k3 J- W) c
  7.     INSERT INTO ta VALUES(100);1 U* z8 E5 C1 s9 H
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件) r; O. ~/ B# h. i/ q
  9.      */
    0 Q% \% t, V% P; u) n9 ^( }
  10.    
    - Z4 D/ k% ?0 t" Z. K/ e
  11.     // 关闭错误报告
    " A/ U9 {$ g3 @8 h( \8 V
  12.      error_reporting(0); " s% g! q; g3 x4 g
  13. + D! }( {9 h" _/ v- k
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    - s8 M' I6 x. \  z7 U5 @4 A4 r
  15.     $dbuser = 'root';            // mysql用户名
    # u$ Y/ i. G0 a$ I) z; R: v. m& A4 Z
  16.     $dbpass = 'root';          // mysql用户名密码
    2 F6 z# F0 {7 P% L4 j% v* H& O
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    : M, `* l( {  I4 b* u
  18.     if(! $conn )* G$ K0 a) _1 Z4 T5 \1 |4 q9 D2 m
  19.     {
    1 G4 F8 w" V" l% `$ k5 U5 F% f) ]
  20.         die('连接失败: ' . mysqli_error($conn));9 X/ b7 e4 s/ I0 T
  21.     }
    ( N+ f" _; T  l
  22.     // 设置编码,防止中文乱码% z2 {: I: o3 |( t! z: J
  23.     mysqli_query($conn , "set names utf8");
    7 p, h% u1 ]; z4 T2 h- M! E
  24.     mysqli_select_db( $conn, 'temp' ); & T9 m  }: P3 G8 Q# Y

  25. + ?, o6 [( {+ i% A
  26.     # mysql 锁 1 v& x1 t% y/ m# o- \0 Q
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    1 J. x8 H7 w7 @) w2 Y
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    & L% V# L$ e, e6 }1 c
  29.     $id = mysqli_result($rs, 0, 0);
    9 S. h* i% M/ o* |
  30.     if($id > 0) 1 e, H* E. H  s" g! t$ r
  31.     { 9 E9 y; v0 e! A1 v) {
  32.         --$id;
    # r4 ~' Y3 O3 p6 G4 c$ U& Q
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    1 r. V% [. F9 v6 [# v( \% U: i
  34.     } 7 s$ `5 x1 r1 K8 R6 e- F$ y
  35. " A$ I) U5 |6 m6 o
  36.     # mysql 解锁
    ! I; V! \. ]8 r# U# _: \0 v/ _
  37.     mysqli_query($conn , 'UNLOCK TABLES');( ~. F! Y7 Z/ x: G* _. A" S
  38.     //查询解锁后的id值
    # Z: r7 N: u' f' b6 {; }/ I  z
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');7 D: z; E; v- L- N. P) _) e( D/ u
  40.     // while($row = mysqli_fetch_assoc($res))
    ) _; S( Y+ q1 _. f' O7 L
  41.     // {
    # K, F8 l* ^; p! m% R3 h8 {2 A
  42.     //     $id = $row['id'];
    2 |. w, C' @: e: F- b: |
  43.     // }
    1 ^% `" q4 v! n% D9 I5 X7 A
  44.     // echo $id;
复制代码

; ?! D/ b% s& j% c$ n5 \0 U, K1 Z# [2 d2 R9 l; u2 ]% }$ H, _) v/ F
4 b  {  O0 |- ], l2 ]2 ?9 U% G
PHP文件锁示例:
  1. /*
    : K/ P. R& o6 }- u
  2.     模拟秒杀活动-- 商品100件) \; o% C6 v* Y3 Z
  3.     CREATE TABLE ta' x/ T, b0 b" t$ H, ]
  4.     (# Z, F2 i$ E+ O! F% t
  5.         id int comment '模拟100件活动商品的数量'
    * G4 S  t3 G# G( S7 K4 O$ _
  6.     );
    0 m6 E3 L! C/ V" f6 X3 M% F
  7.     INSERT INTO ta VALUES(100);
    $ q: a% Q% w1 u, i  S! i! X
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    - c" P- [* y& Y$ c4 K2 G
  9.      */ 8 h. N8 L/ d& n
  10.     9 Q6 c& n' d8 A5 {% ]* z
  11.     // 关闭错误报告* u0 a7 l, A& }) F4 Q( m- D: _
  12.      error_reporting(0);
    7 N2 G, c$ e0 Q0 W4 U, B; ~
  13. - x; [2 E! D% G! P9 k5 p- T. N
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    6 n- W( j% W. r- b; ^! Y2 Z
  15.     $dbuser = 'root';            // mysql用户名
    . ]* i5 w# F- Z; Z- |
  16.     $dbpass = 'root';          // mysql用户名密码
    , }6 R' ]% W* U# r4 ^5 D# F5 I* b
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    5 N6 A+ R3 x7 H( ?
  18.     if(! $conn )9 `5 r# M6 A( T7 T+ t% B. b
  19.     {
    , {9 S" o+ b% }( m( A8 U
  20.         die('连接失败: ' . mysqli_error($conn));
      t- _0 e0 D$ F( a6 K
  21.     }. m0 j$ K7 P$ j" j5 @
  22.     // 设置编码,防止中文乱码3 y0 d5 [2 q: A0 C8 O$ r$ G8 ~4 O: X
  23.     mysqli_query($conn , "set names utf8");  a9 M" [1 ^8 ~7 A5 M
  24.     mysqli_select_db( $conn, 'temp' );
    6 H! y* U; C) l& @

  25. 9 l2 K- V3 l& w9 [" {) t
  26.     # php中的文件锁
    ' b3 s  R: S! `' r+ a" T# z( \2 o
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    ! l! P2 r0 a1 ]  T8 R$ s
  28.     flock($fp, LOCK_EX);// 排他锁 : e( Y& `' r! V# V
  29. & B5 B; Y: g8 ]+ ~* a. n- l9 l
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    / E- l. q! `% N$ Z+ u
  31.     while($row = mysqli_fetch_assoc($retval))
    # S: j8 H- F1 V2 Q% q, h
  32.     {" P9 j7 k6 |) @8 b
  33.         $id =  $row['id'];- z4 \# ~+ \* K1 q
  34.     }
    # m* a/ C5 ]4 L9 }5 N, w
  35.     & B+ x. N8 Y# K( V" ]* w+ C- n
  36.     if($id > 0)
    . X, n+ j' M8 z2 c7 {' z
  37.     { 2 x" z* M- K; ]/ d2 d& m
  38.         --$id;
    ) ?5 E  }) y  `9 ^, D9 F
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); & U- F2 [# O; @; T& j! O
  40.     } % ~0 T* _6 C6 ^6 Q& @4 n
  41.     # php的文件锁,释放锁
    8 r' F2 M! _) _& I3 Z3 F6 N0 F
  42.     flock($fp, LOCK_UN); . \! s1 c& r% m5 q4 w7 L
  43.     fclose($fp);( O0 I! h9 D5 }1 {3 e0 i
  44. ! z0 A2 Z+ x6 Y' H
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');" i" `$ b# f" J' l
  46.     // while($row = mysqli_fetch_assoc($res))1 t+ B" ~5 e; ?% ?+ Q" ~. H
  47.     // {8 K1 ]7 ~6 h4 R7 N6 y
  48.     //     $id = $row['id'];
    + {4 {$ y. ^, l* l2 \8 o: A( K. ^% q! d
  49.     // }
    . S' g7 I! y! V! a3 ^2 k( E# I- P
  50.     // echo $id;
复制代码
3 n' }/ v# I9 u# c) C) Q+ o
5 V7 P- M. c1 N$ z" m6 o
抢券活动实例:
  1. public function envelopeSnatching(){
    5 [5 S8 d. Q5 x' }
  2.         $lingqu = $_POST['type'];! B' ~; v1 h; J& g
  3.         $uid=session('u_id');//用户id
    ; D' o9 w+ @5 `  H1 j) s! R1 m
  4.         if(!$uid){
    # n, s+ Q8 E4 }9 X7 v$ P) U# b% f* f
  5.             $data['msg']='您没登录,请先登录!';* e: y& b$ z# _* w
  6.         }else if(date('Y-m-d') != '2017-12-12'){# Q3 H9 c6 ]( X6 V" {2 _- ?7 \- P
  7.             $data['msg']='不在活动时间内!';
    + c6 Q; W9 v* c6 q, r
  8.         }else{: a7 F  _! ~* W, k4 c# S
  9.             $hours=date('H');//当前小时数
    8 i$ Z% }! V7 l/ k0 f1 A0 f
  10.             if($hours > '09' || $hours > '17'){
    ( M8 \& m' @& N) p$ Z

  11. % I! n2 R1 G% q1 U; ^- e$ N- [; R1 u% p7 O
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    $ o) _$ _  p1 ]. x/ v0 H
  13.                     if($lingqu == 1){% _" L% y0 w. E
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    : ~8 ]% w' Q& w' G7 q
  15.                         if($hours > '09'){7 r4 l4 J7 ]( U3 Q1 S0 d! s$ ^
  16.                             $num=mt_rand(25,28);//优惠券金额
    6 \9 x4 o( y4 y; @: {/ Z
  17.                             $id=1;
    1 _/ N/ p4 K7 @) K
  18.                         }
    ; N6 ^" k3 P2 _4 u/ J9 g
  19.                     }else if($lingqu == 2){
    / x" r8 }1 G' w/ P9 D! B& n7 ]; o
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();2 N" p/ S7 M% k7 H+ R
  21.                         if($hours > '17'){
    - P$ _8 {: J+ h1 i* j( |! Q9 k
  22.                             $num=mt_rand(50,55);//优惠券金额
    : W, H, g+ o  ~( m+ W4 @4 k
  23.                             $id=2;
    , g6 I  x7 V' z* |  |" t9 K
  24.                         }
    " t6 N2 X: x% D
  25.                     }  y' b" y! r& _0 _6 O- z3 ]
  26.                     if(!$id){) H4 Q4 B/ [0 h* n
  27.                         $data['msg']='时间还没到,晚点再来吧。';0 y& ?* v0 S+ E* f' o- D: H( f
  28.                     }else{- F' R: Y$ u" O! F6 }7 s! V
  29.                         if($is_lingqu){% c0 ?8 h  W  Z' w
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    " e  }# P/ x  \) X/ }; q' e
  31.                         }else{
    " J" W9 F3 N& g! w# i# A( Q
  32.                             //锁表' a' ], g  F; ]5 e; U
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');5 Y& @  Q4 B% q
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();* O- E6 Z/ g7 N* e
  35.                             if($active > 0){
    , |6 y+ _' s0 ~( c0 X
  36.                                 //开启事务' f% R! H8 w: ~; L. w
  37.                                 M()->execute('start transaction');5 S9 v: J! W6 W3 I
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));- e8 c, e2 ]7 J( y
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    + j' p$ T1 z! v* ^
  40.                                 $members_preferential    =    M('members_preferential');  i& p# t% Q, H) E1 h) a# R/ C
  41.                                 //对应投资金额,( d. }. D4 x' h7 l) W
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ; T1 f9 j* a5 H& ~, F  @1 e) ~
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');1 k$ o% [$ v* G6 o8 r' S; s5 U7 l$ x
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间. g8 @; ]5 `: {& c/ b
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    5 k! j$ S! N% K9 B
  46.                                 if($save && $add && $add2){+ F8 r% a, L% s* E3 S
  47.                                     //事务提交5 V% @% k( c" v0 @3 o+ [) ?
  48.                                     M()->execute('commit');
    + Z0 a& G' V4 ^
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    6 I& q" p) C  ]) Y: n. O3 E
  50.                                 }else{* u) K4 d  ~7 H  U
  51.                                     //回滚
    5 x3 X1 X- @3 Q- x1 U, i6 c
  52.                                     M()->execute('rollback');! @& k/ n# R+ H) w& N$ I+ q
  53.                                     $data['msg']='未知错误!';
    - ?7 \7 m3 z9 D" Q% i0 |
  54.                                 }
    - r: \6 D, [  i# N  U1 J4 T
  55.                             }else{
    $ K6 {. K% O. A$ i
  56.                                 $data['msg']='红包已领完,你来晚了!';
    ' C# f: @; N/ x
  57.                             }
    ! O! y8 s5 P" h2 w+ b$ M  w9 p
  58.                             M()->execute('UNLOCK TABLES');" J0 K; Z) Q- ~+ B' i0 e
  59.                         }
    # t7 R) J1 K( B# {
  60.                     }7 `& ^( E9 I- L9 \0 v4 L, D0 }' d
  61.                 }else{* z* U$ ^( ^7 x
  62.                     $data['msg']='非法操作!';3 P9 p  o, S8 a# n! y9 v
  63.                 }% Y  @. f! r+ F/ m! @3 T
  64.             }else{3 C$ g% m! T5 B0 n7 H$ ~
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';6 w, a/ U! u) D& q8 r
  66.             }, I1 }1 Y& J) v' ]& E: g
  67.         }& S# C, r7 }% @; ^
  68.         exit(json_encode($data));
    2 N) w# T- e3 W9 ~- e' b6 U
  69.     }
复制代码
! F% T- Z- M( U/ S7 ^8 g/ P5 `, S

. H/ P. ?9 J5 E
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-9-28 06:36 , Processed in 0.118459 second(s), 20 queries .

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