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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9869|回复: 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://请求的脚本
复制代码
: W; i3 i, ^' D2 {
Mysql中的锁语法:
  [" X; e) E7 O8 m& y- c  u) h4 VLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】1 G' m, X0 k( O6 z( s  R8 }- l
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表. e: a& }; O* x; h1 K
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞6 j; |& E. d) Z+ `
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
" J- B0 `" j+ O0 T5 M3 a文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。) q: L5 Y( _3 s, \
测试时,有个文件就行,叫什么名无所谓
总结:
- u) S& g- L' }% v项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:  _& H/ `. S6 l: f3 i3 }
1. 高并发下单时,减库存量时要加锁
# |6 R' J5 \1 n/ Q3 K% P. v* J2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*9 F7 r; ]. t# r% w6 _4 b) C
  2.     模拟秒杀活动-- 商品100件
    9 ~4 e" ^( S( j4 c
  3.     CREATE TABLE ta
    4 {0 n3 O/ E+ u* ]* O0 B2 M" ^5 \
  4.     (" K3 G% R* O9 R9 n+ L' }0 {' j% m
  5.         id int comment '模拟100件活动商品的数量'
    1 t7 A# ?* w  W: r+ D0 G5 r/ T
  6.     );
    3 v# }. x6 K" x7 y3 Q
  7.     INSERT INTO ta VALUES(100);% w6 W( t' Y6 x9 S0 W5 U6 _
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件+ f0 P4 y4 Y2 p2 o6 F
  9.      */
    8 W1 F  s/ }' F* L2 S
  10.    
    $ Q3 n' z; Y' l
  11.     // 关闭错误报告( a2 c1 c5 V- j7 M
  12.      error_reporting(0);
    - A7 g( I/ U, A3 l0 A2 H' O4 A

  13. % `2 M1 O. e5 i  }, U7 m! P
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    - }& h8 e/ y$ q. N
  15.     $dbuser = 'root';            // mysql用户名1 k- f  h: s8 B0 e& O$ i
  16.     $dbpass = 'root';          // mysql用户名密码
    % P& X1 |# W1 U* {
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);6 k3 \# S" ]3 W  @3 `" r
  18.     if(! $conn )
    2 p( V" s9 p7 `( k
  19.     {
      o9 C! a1 k& E2 C8 A- B
  20.         die('连接失败: ' . mysqli_error($conn));
    . I+ F; X0 Y# N$ Q
  21.     }1 z. a5 X# i; I8 r
  22.     // 设置编码,防止中文乱码/ z" O+ j# e: M% N6 D4 w
  23.     mysqli_query($conn , "set names utf8");
    ( x) y6 E$ Y) g7 H6 V: ^! p
  24.     mysqli_select_db( $conn, 'temp' );
    - Q, A2 N  v( j) M
  25. $ ], V' x! [4 d$ M8 _& O- j, ~
  26.     # mysql 锁 7 k3 l+ E/ \# T: I* e4 N' w6 r
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 : a& I4 i) f' W9 ^9 U
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); ' k& q7 Q( ], V1 Z
  29.     $id = mysqli_result($rs, 0, 0);
      p8 E3 ~2 w- S. ]
  30.     if($id > 0) / Q' [, C7 g- y: N" t+ H
  31.     {
    ' r1 C: \2 [) B- X
  32.         --$id; 2 `. S- ]1 _( n. P' p: P# |
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 9 i9 R1 b: L8 h# [7 Z$ l; O- ^
  34.     } # Y6 f% z) i* H- K
  35. # i3 p  x; m! j; O
  36.     # mysql 解锁
    1 U( B# }* D4 z0 z
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    : g! B" j6 t9 Y3 j- m! Q
  38.     //查询解锁后的id值
    6 h# n/ p- T. h/ j/ U5 r/ S7 s6 M2 A
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    1 j6 z8 q, |9 A" J
  40.     // while($row = mysqli_fetch_assoc($res)), |  C  W' ]5 q8 M! z% W( G
  41.     // {6 g# V: {. L+ M  g3 P
  42.     //     $id = $row['id'];$ Z, c' _$ \' I' g9 n2 l
  43.     // }! H' K# O7 J9 p, _! v2 C7 u3 |2 t
  44.     // echo $id;
复制代码
) j$ ~3 O! E( ~- F
; ~: V* i8 R9 X# H; w2 C
, ?% ?8 v% f1 d' [$ Y
PHP文件锁示例:
  1. /*6 A! b% L$ X* j
  2.     模拟秒杀活动-- 商品100件6 |9 ^8 _2 {; o/ B
  3.     CREATE TABLE ta  o0 `  m. A' Q. m+ n0 A5 \' n
  4.     (
      X* y- ?0 l( t4 R& }: g4 e; f- U. f
  5.         id int comment '模拟100件活动商品的数量'0 c, ^4 Q9 d- A: C3 j3 H
  6.     );
    ' t! E8 r. |2 u3 T, v
  7.     INSERT INTO ta VALUES(100);0 ^9 J7 Z, q4 ~4 b" N, z' l0 C
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件4 K7 U! j% z* I% o% P3 P# c
  9.      */ " N: a; g0 G5 v! p! V
  10.    
    + S$ S! s. ]7 [- E7 v  B( }4 K
  11.     // 关闭错误报告
    - B0 }" Q# k; m8 {9 }: k' k
  12.      error_reporting(0);   \) a0 L; V7 }2 a4 L0 d

  13. / x& c6 [! N+ R
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    0 p$ A4 L, _- ^
  15.     $dbuser = 'root';            // mysql用户名
    # B' q- o) c8 z* Q' {
  16.     $dbpass = 'root';          // mysql用户名密码
    2 X' t+ o2 c# j0 i
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    * r" p( c* G6 t' J6 C9 k% W5 w% \
  18.     if(! $conn )
    0 d- u. ]; l: D" B. `
  19.     {
    9 c( Y  V; [+ t9 h* v
  20.         die('连接失败: ' . mysqli_error($conn));
    1 s% q, @  `8 X& l! p: V
  21.     }
    $ u. Z3 A9 S3 \) @' v& Q+ g4 q
  22.     // 设置编码,防止中文乱码
    # Y! L7 \' |# }! e# U3 H
  23.     mysqli_query($conn , "set names utf8");2 f! g5 q: m' w& }" U% ]# t8 m( |, K
  24.     mysqli_select_db( $conn, 'temp' ); ! g/ N9 `3 L) q$ E
  25. ' C/ S- o6 _: u$ ~9 P/ G8 W
  26.     # php中的文件锁
    8 I) v( f% Z2 e5 P
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
      v% L" ^% x0 i; d. F$ v7 D7 G2 M
  28.     flock($fp, LOCK_EX);// 排他锁
    , f- B, E' o5 r
  29. . d! e- f: J' z- O
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    % Y) b9 n6 m: Q, V% B9 j/ S
  31.     while($row = mysqli_fetch_assoc($retval)); T1 b( ^6 ^5 k5 N) _
  32.     {. B# J5 |7 X. z! h! y) K3 _8 B9 n
  33.         $id =  $row['id'];
    * }* N0 I) B2 b! d& l; x
  34.     }
    , Y* L2 @+ J: E+ b3 Z
  35.     ; m! L7 y" I4 Z- }3 K
  36.     if($id > 0)
    " D$ s" i7 @! L; m1 [. w# j
  37.     {
    * \# V: h8 f. Z4 K& a) q" l4 i% P
  38.         --$id; + Z; D9 ?# C# d
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    3 ^' n: ^5 V+ ^! ~5 D9 K7 e
  40.     } 7 X5 t2 u9 E) ^% }0 @/ t; l
  41.     # php的文件锁,释放锁
    7 v* G( a/ |! A  h4 ]- j( a
  42.     flock($fp, LOCK_UN); 1 c  m+ P+ V$ R9 m; i. B: M
  43.     fclose($fp);+ [/ Y( P  ]4 @' ]" Q' q, ?

  44. 7 d4 P" s& k/ _' s
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');$ H' x" C0 f8 P4 i* v7 O5 W
  46.     // while($row = mysqli_fetch_assoc($res))6 g, h0 z/ S7 C& ]# _0 v0 f
  47.     // {
    2 \9 {& ^6 R5 J' y$ K0 F) {
  48.     //     $id = $row['id'];) ^( u# B0 S# E% c1 e, u- [
  49.     // }# h+ {" K1 c* v! G: @$ m
  50.     // echo $id;
复制代码

" ~5 ^5 \# E1 q% g0 X, ^5 w6 x7 W! q) b9 w$ W- [* x! U9 _1 j& [6 ^
抢券活动实例:
  1. public function envelopeSnatching(){2 h$ H2 a( M2 d- o8 [( [' N% w
  2.         $lingqu = $_POST['type'];
    8 h& y# b% z0 n5 w0 z7 c
  3.         $uid=session('u_id');//用户id
    - R* y3 q4 f4 }) C4 p$ c! n
  4.         if(!$uid){
    / t9 p1 C+ |+ w: ?3 f# i
  5.             $data['msg']='您没登录,请先登录!';
    ) }/ Z1 t, F3 g6 C+ U! A& o% Q4 }7 w. L
  6.         }else if(date('Y-m-d') != '2017-12-12'){/ M. B1 M4 a" B8 [* t9 @2 @
  7.             $data['msg']='不在活动时间内!';* f1 H  e7 C) L
  8.         }else{0 s, _4 G9 v3 v8 u4 a; b
  9.             $hours=date('H');//当前小时数
    7 b! e/ v# C: r- p/ s  q
  10.             if($hours > '09' || $hours > '17'){
    ' u! K9 M, H" L. H0 C% \

  11. + J! W$ _: K" ~: n9 n3 h0 x
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    6 n3 m+ o% {! ~; B
  13.                     if($lingqu == 1){
    % ~7 C4 ~/ \- s: m4 @
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    6 ]5 O& a( W/ f; v2 `4 m
  15.                         if($hours > '09'){4 t, \/ w& l2 _& j2 k5 v
  16.                             $num=mt_rand(25,28);//优惠券金额; m: a  V; r& g6 p
  17.                             $id=1;
    ! [3 w1 l! e, r0 x
  18.                         }
    8 ?' o& n7 `" b6 u" g7 G, v0 D1 d0 H
  19.                     }else if($lingqu == 2){
    9 a! G1 C% ^7 F/ Q: w, r& G" X
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    ; i* `  ^# k$ W3 Y7 z
  21.                         if($hours > '17'){' r1 c3 E. z; u1 I, r
  22.                             $num=mt_rand(50,55);//优惠券金额
    4 s4 m8 s1 D, U' G
  23.                             $id=2;
    ( e  V& l0 [' P  _" l0 u; [4 T$ \
  24.                         }
    6 P2 [; N) Z9 z" n. B8 d4 D. S
  25.                     }
    0 g0 B7 J' Y8 ?2 \: [, K
  26.                     if(!$id){5 ^4 d* k# H( U" t8 A1 ~  G
  27.                         $data['msg']='时间还没到,晚点再来吧。';4 i$ P7 _0 V* T. P4 u
  28.                     }else{1 o9 Y! d( L3 ]' G' ^
  29.                         if($is_lingqu){1 ^2 d" b2 ?, @7 w1 M& d
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';3 y. O: S! X' ]; `( q" |$ q* r
  31.                         }else{
    ' T0 w) s* [6 i6 @! m0 x. c) t& T
  32.                             //锁表/ @; r! B" S9 B% w& S/ S9 E0 z
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    2 j; d. ?. t. }2 i' C
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    , n$ A# |2 h' }0 D$ b; m
  35.                             if($active > 0){
    9 D5 d) `, p. I# x) l4 C: s
  36.                                 //开启事务
    $ F# J" T$ ?8 J6 J: A! Z! K, Q
  37.                                 M()->execute('start transaction');
    3 f/ l- d, p+ |! G0 q
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));2 F2 r- f1 n1 M* }, N' n' T
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    9 M2 d3 Q) `- ~$ n; C
  40.                                 $members_preferential    =    M('members_preferential');- q+ ^% n3 q$ k$ j/ O. i4 y( E
  41.                                 //对应投资金额,
    8 r0 C7 i8 U+ d9 X' \, y
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));: M" u3 |$ j7 Z) I5 }. Q, v
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    8 W! W8 V! B  p: {7 f8 F2 R
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间+ N' R; Y1 t& U- v+ a
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券( s0 L1 `. E- ~4 H3 d
  46.                                 if($save && $add && $add2){' \% T. r" j) H7 t7 n& s6 e& L
  47.                                     //事务提交; q% @! x3 Q& a5 Z  G$ W6 o
  48.                                     M()->execute('commit');
    6 _* c6 J" i7 s/ T# Y! D) Y9 N2 X5 x
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';& M) E6 n9 R# u- q+ u' _
  50.                                 }else{
    ' D" v/ v& ~- W$ A
  51.                                     //回滚
    " ]; h) L1 P1 M+ p
  52.                                     M()->execute('rollback');* g  L5 w0 X7 z  Q
  53.                                     $data['msg']='未知错误!';
    3 [5 D% I, r, _( R- m* N! C
  54.                                 }
    5 X+ S; Q3 r: r  H1 I
  55.                             }else{" @& O! C4 `. d6 B  Y7 k- d* o( `
  56.                                 $data['msg']='红包已领完,你来晚了!';, _- U4 f+ `" i6 H; L
  57.                             }
    , V. N) ?9 u  U8 d( s, v
  58.                             M()->execute('UNLOCK TABLES');
    & X9 }: |5 P4 f! B) }
  59.                         }
    8 D+ _8 w7 m& ]) Y) b5 R
  60.                     }! j, Z5 [2 q: S
  61.                 }else{8 s. {& r7 Z1 x' I- X* a6 b' V$ P
  62.                     $data['msg']='非法操作!';: D4 M" Y4 R/ s2 @9 }
  63.                 }
    1 z, n, o. X$ T* G$ @; T
  64.             }else{$ J6 \5 ?/ ?$ n
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    . y& h  Y9 R/ y+ i
  66.             }
    * v6 |( l0 u; @' L
  67.         }7 e: i  R0 F5 L
  68.         exit(json_encode($data));# l, c' b2 S7 \+ {! a4 F
  69.     }
复制代码
/ `+ b. n- e; ]" A$ |& x
, g! `! Z( J! ~8 F/ x9 r+ P1 a& o% f& `
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 00:15 , Processed in 0.065620 second(s), 20 queries .

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