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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

2 K4 H' {3 }3 w, n& p5 f
Mysql中的锁语法:/ F& A6 E# h* N. S
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
; S  ?5 p6 t6 r/ V) b, E( }+ NUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表$ ^, t# _7 W- n6 K+ v, v$ N, k
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞1 Y1 a8 z2 Y1 U
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
9 |3 b  P) h' E: B4 b7 u% E文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
/ x0 J0 R& Q0 I" w5 O: u测试时,有个文件就行,叫什么名无所谓
总结:
! @! J- S+ E. Z0 j项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
6 O$ h8 M9 t9 k/ r" D) S1. 高并发下单时,减库存量时要加锁! N9 f, _# H7 t6 H* Y. v( v
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    / p2 x( Q, ], f5 i1 M3 `0 I
  2.     模拟秒杀活动-- 商品100件/ [% \. k. k9 ~
  3.     CREATE TABLE ta
    2 B: ~: l+ U. j! F# T9 U9 B' P! q
  4.     (
    7 {2 D) U  B1 p/ h
  5.         id int comment '模拟100件活动商品的数量'% K) y$ t6 |/ g7 L1 S  U8 u3 F
  6.     );  [8 Q- x' K: K; u! R& X7 Q
  7.     INSERT INTO ta VALUES(100);( C7 j5 W8 L" q+ ?
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件: p8 O3 x8 W, v4 f5 [
  9.      */ & O2 w. Y8 a" C  k  a
  10.     & Z9 r' j7 b5 i7 |6 h8 g
  11.     // 关闭错误报告" ~, y% z0 `) B
  12.      error_reporting(0); 9 O! `9 Z- L8 D/ ]8 `8 t

  13.   \' k6 [7 w7 k8 z2 K% U' D% ~
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    & K' T" D- g+ {
  15.     $dbuser = 'root';            // mysql用户名
    # e% m9 Q$ q- X' W
  16.     $dbpass = 'root';          // mysql用户名密码
    3 y6 p4 S5 z2 n1 X7 _! M! K3 R# g
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ) j$ l( j3 a3 Q$ c" p! q6 r# K
  18.     if(! $conn )- j) b* `  b6 _1 B; B' L
  19.     {
    4 \4 b1 `: c9 t: U2 p# U, X3 N6 Q
  20.         die('连接失败: ' . mysqli_error($conn));
    ! V! W% C: t- m6 s7 j2 |2 x' {
  21.     }/ I2 c. s8 I3 {  ~
  22.     // 设置编码,防止中文乱码
    - I4 |* U# T6 V7 X; \5 Z/ g2 X
  23.     mysqli_query($conn , "set names utf8");. @0 D; L1 v0 R8 ?
  24.     mysqli_select_db( $conn, 'temp' ); " K7 A8 j' T2 |
  25. / S, S# y+ n- p. ~" q
  26.     # mysql 锁
    2 {1 b, E: r& p  {4 U
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    ( r# w! z4 u6 n- u! ?) o+ t" b1 `  _
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    - u/ o/ H' c# Y5 p9 d( H
  29.     $id = mysqli_result($rs, 0, 0); $ \! x, k5 m' C) E, r& m* N1 |( o
  30.     if($id > 0)
    ' A5 t: ]$ ^+ W; y" s3 O, O% i) d# e
  31.     { ; ^4 L# |+ [" k7 b- F4 ]2 s
  32.         --$id;
    # p8 }- x: s! H: x8 X, \& T# ?( f
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    % H; C, I6 S2 ]9 j, j7 k' Y) B
  34.     } ; s, u2 F4 a$ Y

  35. ' O' P7 Z/ t( J; I, H
  36.     # mysql 解锁 % A6 }: s3 l) c" t2 y- O$ k% C
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    1 P0 Y  L" u+ ^0 ^/ _9 M
  38.     //查询解锁后的id值4 v$ T8 M7 i3 P1 J) d
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ) o& J, P4 d8 q0 L  f
  40.     // while($row = mysqli_fetch_assoc($res)), K6 ^, A. ]5 |! r2 I) S1 H( ?
  41.     // {
    % p* E- _. @( n& p5 F' O8 f$ d5 B
  42.     //     $id = $row['id'];
    ( r) J3 Q7 H7 \. t9 u
  43.     // }
    7 t. {5 x, \& {5 e
  44.     // echo $id;
复制代码
* C' d( c0 a4 `- p( C$ `

# y' t) r7 G3 @6 X  L1 L, y
! \7 L' y5 c; [" D3 I! w# V% A
PHP文件锁示例:
  1. /*: V) g# u, p& D
  2.     模拟秒杀活动-- 商品100件
    3 p+ |% y, X6 \
  3.     CREATE TABLE ta0 N3 Y7 `9 w! M: [2 v5 A
  4.     (
    5 f( v7 f; A- M3 b1 \
  5.         id int comment '模拟100件活动商品的数量'5 }" y/ ~. V! f. e2 |) z
  6.     );: o9 a  o1 n1 I6 Q
  7.     INSERT INTO ta VALUES(100);
    * T! B1 e: ]) _6 h: s- @. Y% y
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件# _, ^3 V" w" Q. {% j
  9.      */
    / U7 @& O, S& i: a  l9 x
  10.    
    1 Q8 e0 c( }) S
  11.     // 关闭错误报告
    ' S% Y- u5 }. O' `
  12.      error_reporting(0);
    ( {7 X2 Q8 W; q; D! R

  13. # P6 R; H7 w4 I1 U
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( s  u$ P0 i* E% n4 v
  15.     $dbuser = 'root';            // mysql用户名- k( T6 s! x3 c8 a) M! C9 ]' F
  16.     $dbpass = 'root';          // mysql用户名密码3 y2 {+ x+ ]/ E. e# ]4 J
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ! q0 K# R, k6 z. ]/ F* i- g
  18.     if(! $conn )" k; c6 O! Y, C7 j% }0 D
  19.     {2 c% ]5 n' Z& G& ]3 f. k) t
  20.         die('连接失败: ' . mysqli_error($conn));
      ~( r1 n8 X/ t+ g5 M
  21.     }' T$ g' O. D5 |& T; {
  22.     // 设置编码,防止中文乱码: |; F4 l# ~& U! I
  23.     mysqli_query($conn , "set names utf8");
    * U% I. |, }' U4 \; O
  24.     mysqli_select_db( $conn, 'temp' ); & k3 w6 V0 y3 f) O+ a8 L$ g

  25. 2 o, l. J! i) n
  26.     # php中的文件锁 . ~, j7 V9 ~! i2 t
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 . k' r8 T! u# q4 y  O& Y' ]4 L8 l7 v
  28.     flock($fp, LOCK_EX);// 排他锁 4 D; ^( w7 q( N8 Y; a' I
  29. 2 x' D: @3 S! ~3 S! V# {  E1 \+ k
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ( {$ I- y+ f9 ^/ ^
  31.     while($row = mysqli_fetch_assoc($retval)), q& v) F" y' N
  32.     {
    ' a6 B# l) p+ Z6 F- y
  33.         $id =  $row['id'];
    8 V& b1 U1 L+ H6 ]2 J, Q
  34.     }- h: e/ g8 W) [0 E; d" \
  35.    
    2 M9 _0 W+ l8 Y" b0 X
  36.     if($id > 0)
    4 g. I2 D7 d9 o. U
  37.     {
    5 u( x! Z8 L6 G& a- v" c- s# q$ c
  38.         --$id; 4 f) ~4 U0 B. e  ^7 D
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    / d9 a" U2 Q; a/ k: q5 T
  40.     }
    % G- t6 s7 a( G5 ]; v
  41.     # php的文件锁,释放锁 + Q. G5 p' Y4 B2 J- l1 ~& j
  42.     flock($fp, LOCK_UN);
    + P' e1 S3 s0 F: e6 x! `4 @
  43.     fclose($fp);
    8 T, K4 z3 Y4 _3 w( A  j$ A* o

  44. $ o5 r1 @! \" F. ~5 c  g
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    : C/ _0 i/ `8 Y, F$ B: {9 g  t
  46.     // while($row = mysqli_fetch_assoc($res))3 ~1 p& ~# C+ p) V7 Q( A
  47.     // {4 s1 j- r7 o/ O7 s
  48.     //     $id = $row['id'];
    5 q& y: C9 K6 u( @7 z' K( X
  49.     // }
    : M; k) v6 i6 m
  50.     // echo $id;
复制代码

0 f8 H& H& G; A% b! A' r2 n% y4 H( H! x) p
抢券活动实例:
  1. public function envelopeSnatching(){/ q4 h9 }. g3 X' w8 p8 B
  2.         $lingqu = $_POST['type'];
    1 R' i+ H) ?8 Z# f8 g5 K4 t% @/ E
  3.         $uid=session('u_id');//用户id
    4 j4 t9 K, ^! O" L4 U4 N
  4.         if(!$uid){
    2 }1 E. v+ {* P; O: c
  5.             $data['msg']='您没登录,请先登录!';+ G/ o7 }. Q$ \! d
  6.         }else if(date('Y-m-d') != '2017-12-12'){3 S( f7 F, y/ _
  7.             $data['msg']='不在活动时间内!';: C: Z1 D8 x2 H* Q/ z3 g
  8.         }else{6 c  R. B& N# N" H. P8 l8 A
  9.             $hours=date('H');//当前小时数
    , w, J. I* a9 y0 p
  10.             if($hours > '09' || $hours > '17'){
    3 g0 H2 E% h: s: \5 G+ w. W

  11. 5 m4 y/ X9 w- J, c7 _) `1 G! m
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    ; Z% ]2 w  ~. n' x5 V( T
  13.                     if($lingqu == 1){
    , J3 b, T4 B0 c' y
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    # ^# {! ~2 E) x" p3 u; w5 U/ p5 G  [
  15.                         if($hours > '09'){( c8 X$ H% }; W! H, y
  16.                             $num=mt_rand(25,28);//优惠券金额0 h  y+ W- `$ G' l. [$ s
  17.                             $id=1;
    ' C, @+ V6 B4 ~4 o2 h: F5 i. a6 H
  18.                         }; G2 t% n6 H; _9 n
  19.                     }else if($lingqu == 2){6 J) `2 O8 H1 [5 t" l
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();) B* b  \+ F; j5 c/ k( m3 t4 D/ C
  21.                         if($hours > '17'){
    $ V; n6 u9 v( p% J: d6 f
  22.                             $num=mt_rand(50,55);//优惠券金额
    6 b' s  F8 \, j) s' B, T
  23.                             $id=2;" [+ e. A8 p' S
  24.                         }6 u/ u. y. ?) d
  25.                     }
    - ~& ]9 R0 v6 E* l8 L2 _$ J: h$ ]9 @
  26.                     if(!$id){3 D0 p  g7 M+ x9 G2 |4 P1 [
  27.                         $data['msg']='时间还没到,晚点再来吧。';+ |9 B8 J# \$ K8 P/ }
  28.                     }else{0 O7 A2 \6 b! M+ y* U' F
  29.                         if($is_lingqu){8 P2 L& p4 u& U
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';. w& n/ q6 {- K
  31.                         }else{
    3 Z( G" X- M. e  T
  32.                             //锁表
    8 a& X- r1 n" ^5 e. W. y7 G1 L
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    - h) s" L6 Y( T. A
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    * Q& x* S3 m( j) X, u  L5 v  A* ~: c  S& V
  35.                             if($active > 0){7 H  F+ E& d6 @% p) L% e& v, U
  36.                                 //开启事务
    : Q0 {  \6 |6 [5 |4 Z4 X0 i
  37.                                 M()->execute('start transaction');+ N4 u5 v5 P% Z) p$ C
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    1 ^9 ~1 c+ g* Q3 J3 S$ ~/ X
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));) A% E6 Y9 d: }- h
  40.                                 $members_preferential    =    M('members_preferential');4 o- }& o' P' P# ~: r% d7 P
  41.                                 //对应投资金额,
    4 j% ^8 \: U/ N0 J2 s
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ! r7 O# i; k# ~7 H2 m
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');4 P, _  `* J7 |
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    8 M% C; n5 @2 [2 t
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ' M! R( @4 \; O) B/ t# r. G  t
  46.                                 if($save && $add && $add2){3 }6 e2 ~5 n$ w5 ^) J
  47.                                     //事务提交/ Q8 C( B7 I4 A6 K' J* _  X! q
  48.                                     M()->execute('commit');% b' \8 v* \2 R* k# F
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';. k" M6 U* a& \4 Y, v  g2 ]% f' I0 K
  50.                                 }else{* w9 ?9 l3 f% z* g( [( }8 v
  51.                                     //回滚0 }% e, u, H8 Z" d
  52.                                     M()->execute('rollback');
    4 V3 B7 ^' Q" w) @+ t0 l
  53.                                     $data['msg']='未知错误!';
    - H# t' Z  D3 P" g+ w4 x
  54.                                 }/ {! V" k/ r- Q3 t! }$ I  Y6 I
  55.                             }else{, g9 `$ ~  f1 \- _9 Q# |
  56.                                 $data['msg']='红包已领完,你来晚了!';
    8 c8 |8 w5 a+ H1 D5 H3 B( c
  57.                             }
    " V7 ~( D) z8 k2 y# ?) T4 D% |
  58.                             M()->execute('UNLOCK TABLES');
    ) T7 j# u) \* U4 \" `
  59.                         }6 U4 ]. |" ]. l* }, V2 n
  60.                     }  Z1 Z2 L# R" u) p5 t, |
  61.                 }else{
    6 X4 O1 `3 c& y
  62.                     $data['msg']='非法操作!';& z5 a4 p0 v; Y4 I. i5 N
  63.                 }
    3 V: E/ A9 H3 E) y* K) _7 D
  64.             }else{7 {5 N: v3 J9 r/ Z: |8 Q
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';7 m* F8 I+ X0 y' S3 D* ^
  66.             }! ]# m. \9 k& ?4 }' K) Z6 k: R) J; A
  67.         }
    % H/ G  l, Y* O6 p7 J" Z
  68.         exit(json_encode($data));
    . u6 g: h8 v  y! i) i% J
  69.     }
复制代码

% T* o5 L0 }4 m6 j) B% }* w1 f$ H( L2 e2 ?# j; m' M
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-20 15:59 , Processed in 0.149386 second(s), 19 queries .

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