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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8370|回复: 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://请求的脚本
复制代码
$ N9 o# N. o* Q
Mysql中的锁语法:
+ L9 M; D8 x: Z1 b. q+ aLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】" h) i) C$ ^  B* I" a2 Q
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表0 G( ~$ X7 \! y5 a) y
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞# f5 H0 s, F* O) B
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
8 Y4 w. u/ s( f5 p0 L( X3 f' E5 d文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。( ]+ s& I$ M% \9 h
测试时,有个文件就行,叫什么名无所谓
总结:
7 s: ~+ G# N  {. g; f  V  }5 P项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
1 X7 }% b* S; ^7 [3 w5 r- w: J8 k3 a1. 高并发下单时,减库存量时要加锁) g. T: R( n3 B4 S6 r
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*' w4 @- C! [( Z6 Q+ v$ [1 C  P- u, I. W
  2.     模拟秒杀活动-- 商品100件! b1 S9 p: J- @' T7 T: z# N
  3.     CREATE TABLE ta
    % q" m+ @4 g  O3 {
  4.     (  a7 v% I, K% G* W$ _
  5.         id int comment '模拟100件活动商品的数量'
    2 \/ |9 w2 d1 x6 g
  6.     );
    * F7 F, l# x  n
  7.     INSERT INTO ta VALUES(100);
    - f( T- L) [9 I$ D0 R4 d6 H7 F
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ! k2 A- Q/ R! f/ S
  9.      */   X; h, J, _) z
  10.    
    3 t3 k$ s# K- A: |
  11.     // 关闭错误报告
    ; x5 i" H/ a% }( k
  12.      error_reporting(0);
    2 ]: k' g- ~9 X; ?2 W' @1 N4 \3 Z. J
  13. 3 O/ ^2 J; ]# a$ j8 e; }6 N
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址& C8 K8 a; S2 ^
  15.     $dbuser = 'root';            // mysql用户名- `- V/ A0 g' R7 ]
  16.     $dbpass = 'root';          // mysql用户名密码9 n3 j) P3 R: ~" E" T% {
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    9 M; {( @: ~7 s2 ?
  18.     if(! $conn )
    8 A- p( O  S; ?! [* `
  19.     {! d7 _. Y8 W8 U* |6 o! z
  20.         die('连接失败: ' . mysqli_error($conn));
    $ [7 J: t5 h/ K
  21.     }
    ' v' ]! [/ u: f8 Q! ~2 o, c
  22.     // 设置编码,防止中文乱码# c+ r7 d7 G% q- Y3 E
  23.     mysqli_query($conn , "set names utf8");
    4 ]* u6 X# F- W
  24.     mysqli_select_db( $conn, 'temp' );
    & A: T9 m3 N( P! p

  25. % U# n" Z% y4 n5 ^! q: d
  26.     # mysql 锁 ; p, R4 g: I( V
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    3 S5 k) P) ?2 t' ]$ X6 ]$ X
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); & O* ~! ]$ H, N' f- K+ n
  29.     $id = mysqli_result($rs, 0, 0);
    7 ~  n9 G5 c& n0 Z% p+ Z9 y
  30.     if($id > 0)
    6 f3 c9 K8 O9 Y( _3 M
  31.     {
    0 t/ _/ F4 G% Z0 ]4 j: C' _# V+ w
  32.         --$id; 9 M  h( Z$ |! }" m( U$ Z2 b
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); ; b8 F  i$ c0 m3 b5 s
  34.     } . v5 g! m7 {0 ?( f

  35. . F7 e: x  B6 ^+ J. ^! s9 V8 M/ [: c+ j
  36.     # mysql 解锁
    8 I' i4 P. W, O! c
  37.     mysqli_query($conn , 'UNLOCK TABLES');. c4 N. ~$ t: j- Q) S
  38.     //查询解锁后的id值: n" r9 @; }* r( I7 f1 r0 U/ ^6 p
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    7 V4 Q/ p. J9 b4 ]/ ~
  40.     // while($row = mysqli_fetch_assoc($res))
      X6 S6 q. m& v( O* L
  41.     // {+ H: z2 j" \9 ?/ k0 C* h' g  \
  42.     //     $id = $row['id'];6 W2 j! _: \% T5 E2 Q( |6 d
  43.     // }( G  f) V# ~8 T4 Y4 q) d9 V8 n6 X9 o
  44.     // echo $id;
复制代码
( ?5 V: M% x, ^+ t
, A1 I, Z3 M) X$ @/ a$ q6 z
/ y) x& P. }! @( a1 E: b
PHP文件锁示例:
  1. /*
    1 V1 q6 O7 I2 U- G' Z& m$ H8 |0 j1 _
  2.     模拟秒杀活动-- 商品100件
    , {4 q0 K9 |0 p& k$ i; }, f/ [
  3.     CREATE TABLE ta) q& Q. X$ D+ {$ S4 V
  4.     (
    4 \% O* p$ T7 X7 K2 x  @7 @
  5.         id int comment '模拟100件活动商品的数量'9 O* C& b! y  j' Q
  6.     );
    # h5 Y( K. p1 X
  7.     INSERT INTO ta VALUES(100);4 \) i' O. U5 F7 U
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件1 ?, w: i& Q: w
  9.      */ " U% _' v& f" u8 J% p
  10.     8 @: w8 o7 T) S1 |1 N7 h! U% f2 k
  11.     // 关闭错误报告/ f- P9 [  Z& c3 i  L# O3 W
  12.      error_reporting(0); : S0 [. p7 J! o0 s) U: k
  13. / d) j" L5 e; s1 c; J. C3 Q
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    / D2 B- ^% j* O, X
  15.     $dbuser = 'root';            // mysql用户名% N8 r  y! N8 k: D+ g5 M9 r
  16.     $dbpass = 'root';          // mysql用户名密码
    1 N$ s& }7 N" V; {
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);+ m1 k4 x' s, d' b2 e. B& i6 V1 C; z
  18.     if(! $conn )
    & {# G$ A; S" U2 t6 D' i
  19.     {
    9 R2 R. h! d# s4 d. n: c' s
  20.         die('连接失败: ' . mysqli_error($conn));: w  y" S1 H1 ]% x+ v
  21.     }
    9 D  f" {) I4 \% r6 `' J+ N1 L+ P
  22.     // 设置编码,防止中文乱码
    : U7 n. X  J' S4 y3 m, ^! s/ z) i
  23.     mysqli_query($conn , "set names utf8");
    7 @5 Y+ _+ L8 ]1 t5 f
  24.     mysqli_select_db( $conn, 'temp' ); ) v" ]2 x- u7 H) |

  25. + R/ Z9 u3 b, I& n4 K2 s; k2 X
  26.     # php中的文件锁 7 n$ G" o3 y  K" R* k2 R
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 7 ?1 Z6 ^/ ?1 [& J  x3 e6 P
  28.     flock($fp, LOCK_EX);// 排他锁
    + v, Q2 d0 B! d) {" t
  29. # m: U& m7 x% E3 H6 S. J) N. z2 j0 d
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    8 X3 m# i; X/ Q& T6 C; \
  31.     while($row = mysqli_fetch_assoc($retval))
    6 x4 E) y0 z2 b: f$ ^5 q
  32.     {- K4 e  o  o! L6 ~' z. q6 ?
  33.         $id =  $row['id'];2 c7 G! ]: R: b
  34.     }; a/ k8 ]0 I7 N- n* N
  35.    
    5 D7 E* b5 f5 m* n; G7 f
  36.     if($id > 0)
    7 @% C+ z, o, @1 N& C
  37.     { 9 y; @. z& p$ E  ?) u6 L
  38.         --$id; " e; Z# H8 t; E* _, I8 ]0 N
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    ' a# g4 \% f6 m2 V3 u; A* E
  40.     } ) V& r3 h  |9 v  e* S! _" u
  41.     # php的文件锁,释放锁 : }4 t7 b. C; R; l
  42.     flock($fp, LOCK_UN);
    . X: X5 |0 F  v/ N- H9 Z  y7 e- ]
  43.     fclose($fp);6 G5 P6 f' y# q; G! M
  44. 7 A8 r) h/ t+ Z
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');  a9 @; ~7 j# F3 |: e) @# {
  46.     // while($row = mysqli_fetch_assoc($res))) w4 _) ]; A% J6 s. {7 ^, ?
  47.     // {
    ) p- _9 t  j5 W+ k
  48.     //     $id = $row['id'];
    + M9 M7 R; c. ?1 Y
  49.     // }
    ) w, t5 A3 u0 ]/ t% z9 D/ L9 j
  50.     // echo $id;
复制代码
; B! x( ]2 u3 {7 z
0 f3 W/ o% M  {7 V. v4 b
抢券活动实例:
  1. public function envelopeSnatching(){
    " ~9 M+ _. f% z  R: ?& D
  2.         $lingqu = $_POST['type'];, [( g. \: H1 c7 E+ f& f
  3.         $uid=session('u_id');//用户id: Q/ p: I& y+ t$ l2 i' L! G6 C# p
  4.         if(!$uid){
    ( F4 i/ _  l7 ]: D. V" ^/ S
  5.             $data['msg']='您没登录,请先登录!';
    : H+ d# R4 P" ]& Q* ~0 \% r8 R
  6.         }else if(date('Y-m-d') != '2017-12-12'){6 ~3 j+ B8 I2 [5 m, h
  7.             $data['msg']='不在活动时间内!';
    ( j6 L9 E1 B" j% K& w
  8.         }else{
    6 O3 u$ v/ ]" k! {  [! w
  9.             $hours=date('H');//当前小时数7 s  K6 m; W7 Y. {4 Z
  10.             if($hours > '09' || $hours > '17'){# e- A6 i6 k7 h; n+ I

  11. & x' y5 q* }$ j  K) n/ {: R
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的9 n! Y8 p: g8 A9 X
  13.                     if($lingqu == 1){
    ' b- ]/ R! v1 s9 u2 ]
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过6 R* `. E6 H4 J' x( w9 m3 Q0 _
  15.                         if($hours > '09'){
    / l; |; Q' Y, P  D  @% x
  16.                             $num=mt_rand(25,28);//优惠券金额: q+ h0 B$ ?. Y2 m* {8 e
  17.                             $id=1;
    0 E( _7 ~) W8 c# q# r
  18.                         }; O: ~9 l+ z& t: k5 D2 ]6 a+ C
  19.                     }else if($lingqu == 2){
    # O! f8 p' U& }! X
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    7 W) N- n9 Q. q0 T4 z( O
  21.                         if($hours > '17'){
    - `; r, s0 Y! g; O$ i9 T/ Q
  22.                             $num=mt_rand(50,55);//优惠券金额
    % A. Z) H+ O% x" j& M
  23.                             $id=2;( H: I1 q9 u0 P  Z2 V! y
  24.                         }
    . U% x+ @9 A! h2 L: D+ Z4 l% ~
  25.                     }
    3 T9 V. ]  t- r1 V1 j0 Q
  26.                     if(!$id){# Z7 R: T9 b) b% R* _  I/ e, B
  27.                         $data['msg']='时间还没到,晚点再来吧。';# J' B1 d& g- `* \$ Y
  28.                     }else{: N. E, x% @5 b
  29.                         if($is_lingqu){/ G/ k) c7 r8 l+ W5 K
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';3 W  K# @. b. j/ q: C5 X6 e  u
  31.                         }else{
    2 n( y3 U, Q7 J6 n& L
  32.                             //锁表: d0 ~! f0 |) j. v$ C5 f
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    4 ~3 l- }$ D; R5 v) e
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();$ s' [* g$ \/ m# k: v8 M
  35.                             if($active > 0){" ]" f8 g( A) Z: }
  36.                                 //开启事务, K: p4 a  D, j" A& s1 {
  37.                                 M()->execute('start transaction');' y3 Q6 [6 l2 ~' f% M9 Q8 Q0 k9 ~
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    ( K6 o- _* O. i" a
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    ; J, i$ P3 }# q" ^( b, A7 ]" m$ ~% T
  40.                                 $members_preferential    =    M('members_preferential');
    4 o' q& u& _" A2 |
  41.                                 //对应投资金额,( E0 q) F8 g  o* ^8 w* i
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));- m, y% I& u2 y" P4 K6 A
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');9 O3 n0 d& |+ B) {$ j: C
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间5 k7 K; r: A3 h  v* ]8 L
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券0 }* _) F2 B6 f4 u& A
  46.                                 if($save && $add && $add2){! R9 t6 `$ X$ S8 v$ y: \
  47.                                     //事务提交* A' Q. v+ W. p9 K1 s7 u
  48.                                     M()->execute('commit');
    : o  z0 v* N" {% e3 o3 r: G
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    + _- |0 _) I- {( H9 F+ m9 c
  50.                                 }else{* L  v% q/ e/ `* H
  51.                                     //回滚
    - o: f& M+ _$ C' o' H( T' M- I. h
  52.                                     M()->execute('rollback');
    1 p9 Z  J: Q8 W! H# _( V$ ~
  53.                                     $data['msg']='未知错误!';
    1 S2 Q$ a" w5 ], Q. @# H6 o: X. _
  54.                                 }
    & J7 \8 W6 [2 a0 }2 K. D  q
  55.                             }else{! H$ g, S* X6 O) k$ q1 O# O9 |
  56.                                 $data['msg']='红包已领完,你来晚了!';
    3 F" n  |! k* H
  57.                             }
    ! M% G7 e: \7 ?5 A) o0 A: T
  58.                             M()->execute('UNLOCK TABLES');
    2 o3 ]5 d1 p" P1 o/ U
  59.                         }* C' j8 m  [' H. ^- v
  60.                     }* F; [* @1 p1 v$ q: L! A
  61.                 }else{1 U7 u4 i) ^/ u! @2 ~: o( {
  62.                     $data['msg']='非法操作!';/ l( x; E. {0 [; Q7 o% p
  63.                 }* Y: S8 t5 e4 I8 F% f
  64.             }else{
    3 P/ z8 L) T4 o4 C" {" H
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    . Z+ e* k* ]3 n2 [) \' s" Q3 g. g8 f) e
  66.             }% ~( E5 r. O) b7 y
  67.         }! u) a, u2 ]2 q2 \, ~
  68.         exit(json_encode($data));4 x, X1 Q9 K4 W+ G6 |6 {7 i
  69.     }
复制代码
: n0 M0 D/ G" x( S. T" B/ H

3 u  w2 o0 @6 o$ |, u1 F% K
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 18:06 , Processed in 0.055251 second(s), 19 queries .

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