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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

6 N/ t# e4 p$ F' b+ r2 H
Mysql中的锁语法:# W- O* n% y% d# F/ S' U# p
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】; n: ^3 Q( A6 t/ f/ S9 h
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
* t! U2 U6 v8 j6 E1 q$ l3 H) }3 uWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞' S! m( T. A  L
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :& u! r" f% m( W* i2 h6 L' ~5 V2 }
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。8 @* [9 ~% K! M+ o7 J8 s
测试时,有个文件就行,叫什么名无所谓
总结:  u# E1 @6 l* ^3 S& b
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:! a) ]5 q3 l3 p* ~7 ?; a7 L! q
1. 高并发下单时,减库存量时要加锁
$ H/ T2 x9 ^' l0 F8 S2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    0 K, L; g: q9 e9 U: L3 B
  2.     模拟秒杀活动-- 商品100件: {7 w' C5 J3 E( t
  3.     CREATE TABLE ta" A+ Y2 d2 _7 G; x
  4.     (! Q5 C& r' i# e' P, ]7 k% @/ h
  5.         id int comment '模拟100件活动商品的数量'; L- c! `2 o$ t! v- P
  6.     );  f/ w7 V; Q0 G7 |) P. P" y
  7.     INSERT INTO ta VALUES(100);9 U" p5 J$ J  d5 ~2 H# u1 q
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    / z+ c5 s5 k6 @: Q  I
  9.      */ ; [! f! x. \# f$ S5 e! r1 f2 J
  10.     & d" B6 g$ M" f. `: P" ]
  11.     // 关闭错误报告7 ^: v# y! U- q: G. N5 O
  12.      error_reporting(0); # }0 |9 u( v& a; u9 N1 C
  13. . G" R& `& j9 q; d/ K: ?/ u
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    + B( ]2 I% W! ?7 c- P
  15.     $dbuser = 'root';            // mysql用户名
    4 V  P0 ]2 H2 g
  16.     $dbpass = 'root';          // mysql用户名密码
    6 R& s+ w; f# ]" h
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ; ~7 p* B5 _' Q( X/ L9 v3 s$ @
  18.     if(! $conn )
    1 H! _2 c( K0 b; I& T
  19.     {
    0 d6 ]% |' c* I1 M4 W0 m2 }
  20.         die('连接失败: ' . mysqli_error($conn));* C, r% m4 H9 Y! g5 W/ W/ R
  21.     }
    0 l7 G; S4 ~2 j/ \9 A9 o7 V
  22.     // 设置编码,防止中文乱码
    3 I, q7 Z3 q, R1 P
  23.     mysqli_query($conn , "set names utf8");
    % ~; h* \4 |! K% Q
  24.     mysqli_select_db( $conn, 'temp' );
    / C, x' M% }% n& ^0 K! x7 {/ [. u

  25. , C' Y6 N. V) L+ e0 t% R6 l9 L
  26.     # mysql 锁 . b# g+ l0 ]$ ^$ u
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    & A0 \; v1 R6 p9 D1 s
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); % N' |- C( F' f  c' a
  29.     $id = mysqli_result($rs, 0, 0); . X3 }( a0 i6 X5 J9 u$ J9 W9 c
  30.     if($id > 0)
    ) f1 ]7 G& e1 K2 n. P( }
  31.     {
    ! x2 q- k2 S. C& t2 J- e/ v
  32.         --$id; . }& Y1 }: B% z; C
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    $ k0 x  B* S" h4 n! t4 w7 V
  34.     }
    + C% N9 @* U1 G+ r
  35. : l9 c" U& D: a
  36.     # mysql 解锁 , n$ H3 o- S. J1 w4 r; g
  37.     mysqli_query($conn , 'UNLOCK TABLES');. Y: W" O! ~$ ~* V, G0 q8 z
  38.     //查询解锁后的id值9 z2 v9 I: {- n5 E/ f
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');4 Q5 P: V' Z7 F' q% _5 }3 Z! E
  40.     // while($row = mysqli_fetch_assoc($res))2 ?4 F- Y$ f3 a
  41.     // {; n' J$ y, _1 z, T
  42.     //     $id = $row['id'];
    + G7 }7 N1 Q, F7 u
  43.     // }0 I4 ^' v9 Q& ^4 p
  44.     // echo $id;
复制代码

5 c4 J6 Q6 W" m# |
: o! O, G1 |* ]0 I

1 N- T1 W, H  {5 L5 e" V
PHP文件锁示例:
  1. /*; e# ?& \; Q$ K4 }- F# ]
  2.     模拟秒杀活动-- 商品100件
    + N0 x. T6 P5 [9 s2 E3 g, |
  3.     CREATE TABLE ta% {% Q0 `" O% ?0 t5 ~
  4.     (
    # ]$ i! T6 u% q* H$ C- G
  5.         id int comment '模拟100件活动商品的数量'. ?! Z! X, c6 z/ o1 U* X  O, z
  6.     );
    6 `1 q' y+ |4 @0 K8 X
  7.     INSERT INTO ta VALUES(100);
    0 T: d2 G" e6 C. K. Q
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件4 C( w, T6 Q' q/ a
  9.      */
    8 K' ^7 a" M( Z( a. m" `
  10.    
    * ?$ n# m" r) O2 I- _
  11.     // 关闭错误报告2 m2 r6 n9 C4 F/ s0 K' L
  12.      error_reporting(0);
    : o* j0 B, v; b2 {8 ?

  13. 4 ]9 Q" N! N% U$ Q
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ! M" h/ K- W5 Q. C& k, z9 ^% Z! z
  15.     $dbuser = 'root';            // mysql用户名) U3 ~# T5 b# l" ^; Q
  16.     $dbpass = 'root';          // mysql用户名密码
    + T5 |: w  M- _% D
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    + H# w$ J& v- H; z( I9 ?! o
  18.     if(! $conn )
    7 ]+ h7 s0 B. b
  19.     {) a% `1 f( i1 ]4 {' ]
  20.         die('连接失败: ' . mysqli_error($conn));6 d) F; T) V7 S/ [7 `8 k
  21.     }' J# p$ C* B& U5 f4 Y
  22.     // 设置编码,防止中文乱码9 h' R$ [1 E, U, V( q$ h  F  S
  23.     mysqli_query($conn , "set names utf8");
    2 T& l6 D+ F7 [2 i% h* a( e1 H4 E
  24.     mysqli_select_db( $conn, 'temp' ); 8 i$ c( U' Z) s2 b" W; ^3 P
  25. + _7 E4 Z  X: ?5 s
  26.     # php中的文件锁 2 Z+ s6 X* X+ z, N1 T8 a
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    3 e" y) e9 `+ @) e+ T! o$ ~- K
  28.     flock($fp, LOCK_EX);// 排他锁
    / a4 J, J- D2 u
  29. ; O8 p2 r: E" R' ]. c
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    : S: ]1 o; N1 R& H# Y' r4 x
  31.     while($row = mysqli_fetch_assoc($retval))
    . W8 E! @& b0 c5 D+ j# `: @4 H
  32.     {
    & n0 f, ?& g: m
  33.         $id =  $row['id'];  F9 t( b. z2 i& [* q( X9 L
  34.     }
    8 Q* ]' N' B2 K( |, @( {3 {/ x( q" P# `
  35.     - S6 v. v# T, n* P: V
  36.     if($id > 0)
    1 l& W3 Z+ a  T/ ]: s
  37.     { ; \! g# Z/ r8 p
  38.         --$id;
    6 w  g0 g4 v  B: N- s
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); & T! m3 V4 d# j1 N1 r6 L- s
  40.     }
    # q9 k5 S9 R& r* c0 h5 U4 a
  41.     # php的文件锁,释放锁 . F9 X) D6 O1 y, c. B6 N- I$ s
  42.     flock($fp, LOCK_UN);
    # G  Q9 @1 t4 d  y& I) G* {
  43.     fclose($fp);% c- O  o# m0 `

  44. $ i+ C7 e5 g4 i& S. M0 h
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');1 V! [0 ^2 M% v/ l1 ?
  46.     // while($row = mysqli_fetch_assoc($res))3 _  ]2 e: w9 K0 S6 w/ ]$ ^8 V. `" a
  47.     // {
    - t; S! v; Q; i3 I6 n+ |& ]
  48.     //     $id = $row['id'];- E; N) Y2 w$ |: A6 f
  49.     // }  P* I# {3 t: n2 f7 r
  50.     // echo $id;
复制代码

  ^4 H7 p0 R8 f7 s0 q4 ?6 n1 D- e4 C. t4 k6 }
抢券活动实例:
  1. public function envelopeSnatching(){6 h  S9 r' j) w/ m4 e9 B7 c
  2.         $lingqu = $_POST['type'];& L) v- Z, N" j9 C9 m9 m
  3.         $uid=session('u_id');//用户id
      k; H" q9 V$ @4 A6 |7 e0 D2 g* H
  4.         if(!$uid){
    ; I! C: L/ Z- P2 a
  5.             $data['msg']='您没登录,请先登录!';
    0 U# J/ l3 p: O! [' R! h9 I2 z1 Z; Q; Q4 Y
  6.         }else if(date('Y-m-d') != '2017-12-12'){# ]' N. M3 ^! F1 E! }* g0 i
  7.             $data['msg']='不在活动时间内!';6 i- Q0 m2 d% a% M
  8.         }else{; A# ^. x( ~9 a& [  i1 L
  9.             $hours=date('H');//当前小时数
    5 v# d9 [0 V! c" B$ g! j" O
  10.             if($hours > '09' || $hours > '17'){$ r$ }' v7 K/ @8 h& N. \$ R2 k3 k- M

  11. " a( \8 y' z9 a. M
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    2 {7 G6 W+ Z" _9 J0 H$ s8 b/ f
  13.                     if($lingqu == 1){
    & x$ }9 E* G  z: C9 a. L* ^6 ^
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
      w* \1 B& N& M) M" g
  15.                         if($hours > '09'){
    2 ~- e5 ?3 ]5 }1 b! y- ]9 S
  16.                             $num=mt_rand(25,28);//优惠券金额* e; z1 e5 N' Z# B) R8 o, j+ f
  17.                             $id=1;
    + ]& u' o% ]1 v: t2 H% I' J
  18.                         }
    ' R" H: U! E( ]' c1 R
  19.                     }else if($lingqu == 2){
    5 @: R! R" A4 X5 h( @
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();4 h6 z2 M' h3 F& f
  21.                         if($hours > '17'){
    ' K* C  y4 w" X7 T
  22.                             $num=mt_rand(50,55);//优惠券金额
    3 t- v% \" N, s" k1 I& }
  23.                             $id=2;
    9 l" z. L/ H" d$ C: m
  24.                         }7 L. e; }: q) d4 o0 v
  25.                     }2 Q  Q  c$ ?  \2 P4 G8 @  ?
  26.                     if(!$id){: o+ R" V2 F+ g2 P2 b
  27.                         $data['msg']='时间还没到,晚点再来吧。';" W! W5 V. }) [( w
  28.                     }else{
    ' Z  Q3 @, L$ K0 s' O
  29.                         if($is_lingqu){
      R" \# @" Y1 c/ u
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';) T( Z2 p2 O/ ~$ ^. X% h
  31.                         }else{/ j$ l: A3 @9 P$ _3 `
  32.                             //锁表/ q" e7 w& x$ o9 H" O
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    * [; k( |3 m) q+ ~
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();# ^: f$ W- t2 |- N/ B  v
  35.                             if($active > 0){
    7 `6 E( [5 [  c& R' f/ Q, ~
  36.                                 //开启事务
    , }2 K+ L* P9 k; H( F; D
  37.                                 M()->execute('start transaction');8 d! n& s5 C0 R! T' M6 w
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));6 [& a6 I3 S# ~
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));/ K8 a  e% s# [7 H; x) d+ j, M* U
  40.                                 $members_preferential    =    M('members_preferential');
    % V9 u+ d" t' x6 t0 O2 `
  41.                                 //对应投资金额,$ Y; S, ~- d& E8 l+ @0 e( x! _4 p% ^5 `
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
      i5 n; N8 H4 I# G1 V8 @$ h. F
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    1 ]' N, \/ t8 _/ P3 Y7 v
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间. v6 J3 Q' L+ P# I/ k
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    $ k) P5 }$ w& v
  46.                                 if($save && $add && $add2){9 H3 I! K% m' ^& c0 e# f! e+ L; L- N
  47.                                     //事务提交
      L1 p% p4 `* \
  48.                                     M()->execute('commit');# e/ l, E1 b( ?$ I, R- l2 K+ _! }
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';2 j8 n+ D/ H% @# C. }
  50.                                 }else{4 x( s( p+ a# n( F
  51.                                     //回滚% M0 p' n: r! `! L- n
  52.                                     M()->execute('rollback');
    9 n& g8 a& W" R- ]2 ^1 u) M
  53.                                     $data['msg']='未知错误!';: m- w+ X! i& ]$ J
  54.                                 }
    + o$ {/ F& V, X$ O
  55.                             }else{
    & f8 \+ S  G) r5 t
  56.                                 $data['msg']='红包已领完,你来晚了!';
    % r* Y$ b5 {8 p
  57.                             }
    " R, Q$ N6 Y, r, {# W1 i
  58.                             M()->execute('UNLOCK TABLES');, S* b- @. T7 N5 p! A3 {4 `
  59.                         }
    0 c7 m) E4 E; e! v; W+ j8 N- n
  60.                     }3 \6 {/ O2 X) n, h6 V- ]: c3 w9 _7 N
  61.                 }else{8 H& f+ ?# i) B% ]+ h; i3 }: w
  62.                     $data['msg']='非法操作!';* @$ r, g7 f" ~- k( j: F
  63.                 }
    - n% K; r* l0 X- V. C- u, [9 b, n4 }
  64.             }else{
    # ?4 q' F/ E$ N1 l
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    : k& v3 g1 N, e" P! p
  66.             }
    5 _* o7 `, ]( }. @
  67.         }6 U- I2 M4 r7 Q; ^6 W& X6 H
  68.         exit(json_encode($data));
    ( H0 F% u- J- y) Y; C. @  j+ v& A
  69.     }
复制代码
3 g- G: U  @  B+ C
4 C" |' i  n% b, O5 v4 `$ [5 w
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 18:43 , Processed in 0.070337 second(s), 19 queries .

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