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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8205|回复: 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://请求的脚本
复制代码
5 e+ a) n, p/ F& Q% |( c
Mysql中的锁语法:: M9 g7 j" X; Z7 m0 K7 l1 @
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
/ t3 a+ P, ]1 n' n( S8 E% J9 }UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
5 {! e" K) Q- YWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞2 d/ P# x  y0 W3 Y$ e
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
5 j) A0 E5 @5 g, s% `' U  w文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。( k- K1 S( c6 U& J( c0 {
测试时,有个文件就行,叫什么名无所谓
总结:' D, g5 v+ u! v' k, H
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:  w+ B( q+ G3 t4 t
1. 高并发下单时,减库存量时要加锁+ U1 \" z) z7 @" D* c4 _
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*5 I8 x- i6 k$ x& Z
  2.     模拟秒杀活动-- 商品100件0 Z( F$ s: B* J9 W3 G2 S+ C8 i
  3.     CREATE TABLE ta
    ; l' p$ A/ I  Q' B+ D7 n% @
  4.     (
    3 T2 D* W( q3 Y3 _5 g8 y
  5.         id int comment '模拟100件活动商品的数量'
    0 |2 `& _' Q9 F: x: d! t
  6.     );4 _$ V, k! o" n  N
  7.     INSERT INTO ta VALUES(100);+ O, u  z! |5 Q7 k8 g
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件6 l. ?8 o# j) Y: n7 G0 x
  9.      */
    ( P5 y% _) A0 E( V
  10.     8 H+ r  u1 S; E# U4 P7 V0 Z
  11.     // 关闭错误报告" U3 v& T5 {4 a
  12.      error_reporting(0); . K' @# P4 s' Y% u0 g7 d' f4 M5 T
  13.   J9 y( R1 Y8 e. \  q
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址/ E8 S3 _7 j8 Y, u1 `' R; u% C- Z. {
  15.     $dbuser = 'root';            // mysql用户名
    ' |+ K- Z  k3 S0 `5 [6 Y% Z- ^* n
  16.     $dbpass = 'root';          // mysql用户名密码( D. Y8 C- d) y, L/ [8 b
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);% M5 b  D# m/ S$ ~$ a; V8 A6 q6 G
  18.     if(! $conn )7 [4 a0 f! w0 P# Z2 q, o
  19.     {0 c! o* K2 q* M/ q1 @5 |
  20.         die('连接失败: ' . mysqli_error($conn));
    % z9 {* a- ~8 w' Z% P) H! G- k) G
  21.     }
    + a5 s1 K/ o3 P5 [, w, r2 ]) S& m) j
  22.     // 设置编码,防止中文乱码
    ; U1 I8 {6 i3 X0 F) u& s
  23.     mysqli_query($conn , "set names utf8");3 G" [8 B4 H5 s/ i( ?
  24.     mysqli_select_db( $conn, 'temp' );
    " x# v: ]5 @0 Y4 u" E
  25. 7 E: A9 x  p/ U3 E% x- {
  26.     # mysql 锁 : X9 S' f) \, ^9 v7 P/ ^
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ! M3 }( L1 n& n
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 4 K; m. B6 V' l& C; H) j$ T
  29.     $id = mysqli_result($rs, 0, 0);
    $ o1 I  [* Q' O4 l( J
  30.     if($id > 0) / |- L7 h  h7 }. x
  31.     { 8 t9 A) L8 ^8 z. a$ W
  32.         --$id;
    & z/ ~- {# l1 `) u
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 2 i2 g5 l: s: Z  I
  34.     } 0 ?" e& E3 z9 n# p+ a( T
  35. 4 k4 [; p2 u1 v6 A
  36.     # mysql 解锁 " {" o/ D# c, f: l
  37.     mysqli_query($conn , 'UNLOCK TABLES');5 N4 z& n/ ]3 s: ?/ S
  38.     //查询解锁后的id值
    ' K  G$ X9 V! T& G9 t
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ' H# J) _6 G4 z9 l: Z8 z
  40.     // while($row = mysqli_fetch_assoc($res))0 i$ ^4 t. {. c- j) ?$ D- G( ~. `- l
  41.     // {
    2 w; S0 @. U" U+ u/ i+ f
  42.     //     $id = $row['id'];2 v: A" g& h* s/ m( ]; V% h' x
  43.     // }
    $ h# g. U/ }' B3 Z/ _$ `
  44.     // echo $id;
复制代码

3 u) ]; ~8 }' k& Z! v" T9 y8 ?+ }2 O$ W1 `1 w" Y2 c7 w/ {5 T

8 Q2 N1 s& F5 @$ l
PHP文件锁示例:
  1. /*: d4 e1 ?& M- F$ Q  }: e/ S" H1 Q
  2.     模拟秒杀活动-- 商品100件
    0 q, D, G$ G  j! I
  3.     CREATE TABLE ta1 R& L+ T5 j' u
  4.     (7 j. o2 V% \& H* H0 }
  5.         id int comment '模拟100件活动商品的数量'0 `, G: h( v! w+ }, D7 @. d' o! D
  6.     );
    9 `- b5 p3 L, }( t
  7.     INSERT INTO ta VALUES(100);" H7 `, V5 h; S  f  \
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ! ]/ x8 s! Y8 ]$ p( z% X
  9.      */
    8 m# Z& ?$ ~2 c5 f- J
  10.     4 a- U- |% Z7 i- H& n2 P4 E
  11.     // 关闭错误报告
    1 M- [+ S- p0 k( v  }' Y
  12.      error_reporting(0); 6 K% _0 t2 d5 l, y3 {

  13. $ g, M& b' [0 z# o
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    1 N3 _! `$ z2 ?5 J
  15.     $dbuser = 'root';            // mysql用户名3 `# U4 g0 q) i  v2 U+ ~
  16.     $dbpass = 'root';          // mysql用户名密码
    7 ?: ~# Y) B# d3 T8 n' u
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);( Y# ^6 J) |9 p3 p3 |
  18.     if(! $conn )
    * L7 x" N& h, g* B9 A. U4 o* @3 l) g
  19.     {& W: x4 _. v, Z8 S2 n! a, `
  20.         die('连接失败: ' . mysqli_error($conn));. v  P8 J- ~; [3 [/ X" D6 b
  21.     }: g9 v7 j- q1 o% S8 B
  22.     // 设置编码,防止中文乱码# ~4 V/ p+ T7 B  I
  23.     mysqli_query($conn , "set names utf8");+ Y/ u+ h) x" Y' g" r
  24.     mysqli_select_db( $conn, 'temp' ); ) u  E) r# ?( r! T3 L4 C

  25. ( r, O! P/ k, r* H
  26.     # php中的文件锁
    / v# f8 I. T& O7 M- {9 G
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 7 D( h* J% a8 k- D3 Z$ u' e! J
  28.     flock($fp, LOCK_EX);// 排他锁 * I$ ?5 Y) l7 M- A

  29. 1 Y$ x  f8 e, _: H0 f* ^8 N! S$ I
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 0 ^) i& ^( c/ d6 Q4 C! c: v
  31.     while($row = mysqli_fetch_assoc($retval))# B+ w9 Z& O1 K1 [
  32.     {% x2 r: ?: ^4 ]' t3 n% c
  33.         $id =  $row['id'];
    ! I1 R2 \( o5 q- L! |
  34.     }8 H; U3 k. h/ w5 U% Z. \
  35.    
    ! L# J/ o" G' P- Q- x( h
  36.     if($id > 0)
    & N2 u1 B2 R' f) N
  37.     { 9 A' B3 B7 s0 Z8 V3 p  J$ A& U
  38.         --$id; 9 H- T9 O$ C0 }3 v% h$ H9 Z: ~
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 1 {% Y- h% m/ V' \. K
  40.     }
    9 }4 M" S' _1 Z; [. _* D% _% O) W
  41.     # php的文件锁,释放锁
    3 g5 R- I5 w0 U6 C# h. e- Z
  42.     flock($fp, LOCK_UN); : N$ m$ {4 |& {" S
  43.     fclose($fp);- u% C* Q. E, s  Y- D
  44. $ F/ f  ~9 m+ t1 J$ o9 a3 S. Y
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');, m6 K: J+ y. N/ a7 v9 t0 i) m. a/ X
  46.     // while($row = mysqli_fetch_assoc($res)); A8 ]9 `& O, L" p0 }5 n
  47.     // {: u; s# U( R9 U: L7 ^" x4 }! o
  48.     //     $id = $row['id'];+ `( G8 e4 W2 a' N- m
  49.     // }
    * m; z* q1 c0 _1 Z4 ~
  50.     // echo $id;
复制代码

) t$ X& U. i2 X4 ~' K6 I
3 i- |. K; o) Q6 \4 v
抢券活动实例:
  1. public function envelopeSnatching(){& X/ H4 X& t# F+ Y: @3 r& m) r: n% c
  2.         $lingqu = $_POST['type'];
    . d- f8 B8 h/ j
  3.         $uid=session('u_id');//用户id
    ) l; h; R4 O7 A2 X3 \, k: P% ?
  4.         if(!$uid){
    5 ^# T) d6 e6 F* \# H0 \
  5.             $data['msg']='您没登录,请先登录!';, L% T+ _! L  _1 _/ `3 [
  6.         }else if(date('Y-m-d') != '2017-12-12'){8 l, i6 X5 b6 \# E
  7.             $data['msg']='不在活动时间内!';
    . Y  C" B+ f  N: L3 ~; K! E
  8.         }else{
    - @' c+ H3 u4 T
  9.             $hours=date('H');//当前小时数
    # |4 M2 W9 Q# b- n) V, E5 d
  10.             if($hours > '09' || $hours > '17'){
    . v9 p0 V" j* Z4 J6 i& G
  11. # _- L! }, z1 F
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    / m7 l+ B6 d$ y& @+ {: M
  13.                     if($lingqu == 1){5 Q; H' [7 y' \1 g4 I4 s" I. N
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    ) k8 }9 j' z5 R( x2 {) b1 s
  15.                         if($hours > '09'){8 W! U3 s  P! G9 E. o/ c
  16.                             $num=mt_rand(25,28);//优惠券金额
    ! x& u! j/ K  k% ~
  17.                             $id=1;
    / U, A7 Y4 x+ d# _( i
  18.                         }. B! m8 p3 l$ C- }3 u( V* r1 M
  19.                     }else if($lingqu == 2){, A7 b' v3 p- S( b! ~+ T
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();8 G  m1 Y2 [& m5 |6 c
  21.                         if($hours > '17'){9 O# ^- Z$ K: x! s( |
  22.                             $num=mt_rand(50,55);//优惠券金额& Q! K" a; m! J$ W! R
  23.                             $id=2;
    " v/ X8 Y. P1 O8 z6 h; ^0 A0 S  R* R
  24.                         }
    : n) \. r# G' Q. A* \
  25.                     }# u3 ?- ^. m( Z1 e" z1 ]
  26.                     if(!$id){" }" S  Y$ U+ [; ^9 R
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    ! l0 A: V# P) @; K0 Y1 Z
  28.                     }else{' }" y# I/ B" Q7 o) [  r6 g
  29.                         if($is_lingqu){
    2 Z1 q' l* c( x/ x4 e
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
      j2 U% I, v) u
  31.                         }else{
    : B$ Q; o/ A  P; K! e/ J8 ]
  32.                             //锁表
    " k. Y7 Q; h1 I, g% v
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');" ?1 c; S* X) u4 h7 s9 H3 R8 c
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();, r) S' Y+ X: t( r/ c2 d5 h+ }6 Z
  35.                             if($active > 0){* u9 b4 N; |* u
  36.                                 //开启事务
    ) D$ m) }+ p* R! E2 v
  37.                                 M()->execute('start transaction');* s. _- ~1 Z* [3 F
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    3 J7 m; I; ^2 d9 }* I7 c; T; a
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
      T- Q, X7 B! g% Y2 h' p3 A) t
  40.                                 $members_preferential    =    M('members_preferential');
    . G. |7 Q' v$ G# w2 [- m( F2 x
  41.                                 //对应投资金额,# `/ z* ?- n0 o. V- d  d9 l
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));6 e6 T9 I  F, U4 p4 t
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    $ o# q& g4 W  f5 A0 q
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间4 z  m$ W+ a8 l
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券- K, @2 R6 ?- K- z& d' I  r8 q& |2 O
  46.                                 if($save && $add && $add2){
    % ]3 h/ b! W: Y/ K% \# O
  47.                                     //事务提交7 T5 M- [9 \8 [& n* n% n3 V0 l/ e! i
  48.                                     M()->execute('commit');8 m7 Z2 p6 B. A: @9 J- z
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';+ x. ]5 C: p& F+ o3 y: L4 P% C  m
  50.                                 }else{
    1 i& K$ U* h) D  U
  51.                                     //回滚
    7 w: n% Q7 P) }. Z& |) i7 N
  52.                                     M()->execute('rollback');
    . ?* G0 g" t: x) U, N
  53.                                     $data['msg']='未知错误!';
    2 d4 C' `- @0 e! g4 R  q1 b
  54.                                 }
    - S  L+ U+ \- }4 r4 D# t! n6 U
  55.                             }else{
      ?$ h* Z% H: F. C6 W* m
  56.                                 $data['msg']='红包已领完,你来晚了!';# ]) W# I* E1 T+ K1 g9 C3 _+ n
  57.                             }7 [2 o; A' Q7 Z: a+ M9 F6 |6 o
  58.                             M()->execute('UNLOCK TABLES');
      n9 j! Z1 s, x) y
  59.                         }7 k: R4 u( \  P$ Z
  60.                     }
      h6 C; r  T& T+ c- |# B
  61.                 }else{! E) h6 i, p, s/ v
  62.                     $data['msg']='非法操作!';
    ! ^, v* E' f& h8 i( }
  63.                 }7 v# K. O) g3 R
  64.             }else{
    6 b' G) I- B/ D8 M( b
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ) Z  l$ Y& }' {; I. s) t8 E% }
  66.             }# F+ _/ L0 ^" S
  67.         }
    8 {: r& V/ y1 C8 t* i
  68.         exit(json_encode($data));
    % y3 k  z, G1 U% t2 u; q- f, k
  69.     }
复制代码

* c$ J. N2 O" F( ]
2 H5 D" e% [/ h" i% P
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 08:15 , Processed in 0.055028 second(s), 19 queries .

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