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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8369|回复: 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://请求的脚本
复制代码
7 S3 Z- a$ ^" I% j( ?' N
Mysql中的锁语法:) V9 ]% i* ~  F4 I: e* A
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】, p5 H7 a# C9 O& i  E$ ^' x4 U
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表" V# l! P; Z0 D! E+ H
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
$ @. A' Y3 _2 n- [7 H注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
0 Y# c) G9 T2 I' T9 P5 _8 N文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
! t6 J1 Y( q9 ~3 B; q/ _* L: a测试时,有个文件就行,叫什么名无所谓
总结:
* C# L; |) d5 \2 D7 |项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:  K) Q% O9 l# |
1. 高并发下单时,减库存量时要加锁0 V9 I$ z5 S! F4 W
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    6 X8 h  _) D5 H  O
  2.     模拟秒杀活动-- 商品100件
    4 `+ Y( s  d) l1 l/ l2 P8 ~1 S3 m3 B
  3.     CREATE TABLE ta1 c. K. ?1 L4 O" g1 Y% Z8 s
  4.     (4 ^; e4 v  c! k, _3 S" M. g
  5.         id int comment '模拟100件活动商品的数量'
      N" R; @' l0 @$ l
  6.     );
    - t) d  ^' u$ }7 r
  7.     INSERT INTO ta VALUES(100);
    & L* ]4 d) \& N1 q
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    5 i# T8 D  ~) l8 N6 d. ]
  9.      */
    " e, `$ k: ~" }
  10.       Y* ?7 d; ^- i% x$ c4 m" F
  11.     // 关闭错误报告& F9 W  _" V) x1 e. z  a: l6 X% \
  12.      error_reporting(0); % ^' ]: n2 X- i# h$ h1 F" T, o1 a
  13.   b8 L+ y# Y! `6 @. o; o6 j
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( _$ ^4 L/ i/ g' U- O' i
  15.     $dbuser = 'root';            // mysql用户名  `* P1 c( w" {) D6 k  @" f
  16.     $dbpass = 'root';          // mysql用户名密码: K& O2 X( U3 M' `
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ; G2 R, Y7 s, Q# d5 j3 n* {/ R0 m
  18.     if(! $conn )( u/ h, ?/ `; L' f
  19.     {5 s' G% _4 K- x1 ]( M% g
  20.         die('连接失败: ' . mysqli_error($conn));  h2 l9 a8 p2 K5 z! @
  21.     }
    4 P) _; C1 t/ s) ^9 _1 f
  22.     // 设置编码,防止中文乱码2 z1 V: m& G# `8 {0 q6 m
  23.     mysqli_query($conn , "set names utf8");
    " o) r0 g* ^1 T4 B" Q% j* J. E& d
  24.     mysqli_select_db( $conn, 'temp' ); % [" b7 e( R% m' I- r% i

  25. . X. d- R# ^/ v. R% c4 v5 a0 g- s
  26.     # mysql 锁
    / ?- A4 Z! b2 i
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    , p8 ^7 y, `  k
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 8 U+ x- d8 v3 ~# o( `- \
  29.     $id = mysqli_result($rs, 0, 0); # o/ k7 S) J) }( d8 @
  30.     if($id > 0)
    ; m- R3 G/ d" g$ E* V6 V. A
  31.     {
      N1 ~2 G; ^5 q8 l# k/ r6 a# B
  32.         --$id;
    * B& Q$ h6 J( X% z; M9 |
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    $ F  a+ Y" S/ \- }/ P" |1 S, w3 N
  34.     } 4 Q, x! S( u/ v" ?
  35. * z) J: v3 p+ C$ A
  36.     # mysql 解锁
    & {4 a6 s, J/ z+ d& l# G, c; }& \
  37.     mysqli_query($conn , 'UNLOCK TABLES');0 w: k7 [' d3 f2 T. _
  38.     //查询解锁后的id值
    7 j2 k# d: x8 Y) P7 D9 Q
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    3 C* D. z4 C% {4 j6 M7 ~: T" ~
  40.     // while($row = mysqli_fetch_assoc($res))' q- `2 L, U2 o" a; m) E
  41.     // {, L' R3 `, W2 S% b
  42.     //     $id = $row['id'];
    1 |- _2 C8 o( c9 y) e
  43.     // }1 ]# k$ K& R' S; t2 k- R0 @
  44.     // echo $id;
复制代码
: D5 O' X' s- p( x
. G7 q- U% @: l' _4 X$ S3 W

* u9 C: T. t. v' ?* q+ d6 C
PHP文件锁示例:
  1. /*
    ; |! c3 V, {1 A
  2.     模拟秒杀活动-- 商品100件5 b2 B* A. J1 ^3 b' `9 s
  3.     CREATE TABLE ta
    # |6 c1 `$ D# e3 O) Y6 _
  4.     (
    6 E/ q9 H9 X; n$ |
  5.         id int comment '模拟100件活动商品的数量'
    - J$ J* s2 {' [5 w! b
  6.     );
    2 {9 i; W1 x) Y9 c
  7.     INSERT INTO ta VALUES(100);7 A4 R: `3 z# G4 @3 S. R
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件  h2 w* Q! _: B+ A( ~
  9.      */ : D; o) i5 _0 K- F7 c  v: p" }
  10.     2 ~6 N# r7 a3 s
  11.     // 关闭错误报告2 B6 a( O0 }9 \- ]
  12.      error_reporting(0);
    . ^; }9 H* x/ ?7 S* ^& E, s
  13. 8 Q/ B" X7 F. ~/ h: c9 H7 O3 y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    4 o" W) y, f/ H8 D4 t
  15.     $dbuser = 'root';            // mysql用户名
    * ?- C, T' J+ _* x: ~$ x$ i
  16.     $dbpass = 'root';          // mysql用户名密码7 J' }( D, p* D/ M, Y
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);6 X( F* t7 W. A' G3 }; |; l
  18.     if(! $conn )3 H, d0 L8 T6 l: F$ ~
  19.     {+ J" J5 ^; d4 ?' a+ A
  20.         die('连接失败: ' . mysqli_error($conn));2 C) r, h( \* M; w
  21.     }3 @5 C$ `3 N* O" }) P( E
  22.     // 设置编码,防止中文乱码
    0 y9 I5 |* E  r: m8 T' q
  23.     mysqli_query($conn , "set names utf8");7 ~$ d+ ~3 J* U/ _7 q, h. i: X& U
  24.     mysqli_select_db( $conn, 'temp' ); 4 N% F' ~: t; l) {2 W" L, U
  25.   t3 W0 V# T' m/ R% B& n3 |: t* U
  26.     # php中的文件锁
    4 ^+ t% v7 M7 M  z
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 , f! B7 u& U2 Y, D: s
  28.     flock($fp, LOCK_EX);// 排他锁 $ D* q( |3 I/ n, r4 p+ ]# @) Q/ b
  29. % ?: ^( i, _7 f
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    - k& S0 f) c1 D4 b
  31.     while($row = mysqli_fetch_assoc($retval))
    & J3 J( `/ Z; q
  32.     {& ^7 L, D7 t( v# O
  33.         $id =  $row['id'];0 q4 x, F$ c& P, _7 p! s
  34.     }
    . ~! A1 Q" k( F5 z4 x
  35.     ( i, }, j- n" g  z" m! a
  36.     if($id > 0) ! i- q2 A2 p& L& `& Q
  37.     { 7 f6 c+ M8 O, v( y/ f
  38.         --$id;
    0 x* ^5 B' s  l& q$ K9 \
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 5 l6 B3 I( Y. {; Y- \5 }! s
  40.     } 1 D0 P# Y9 ]7 F2 ?* S
  41.     # php的文件锁,释放锁
    ! }  C$ g. q% d5 `$ _0 y
  42.     flock($fp, LOCK_UN); ( a+ F( o2 {, [* y( c
  43.     fclose($fp);; K, |5 \; i! G0 T' F4 Z+ r
  44. 9 e0 B' S5 S- q9 r6 ]4 i) r2 c/ i
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');8 l7 M7 |2 N* ~& s* S
  46.     // while($row = mysqli_fetch_assoc($res))
    6 ]! B) C, Q8 l2 D* f7 D# v5 f4 @
  47.     // {
    : Q0 K; ?; i: l2 `$ T* y
  48.     //     $id = $row['id'];% S4 q; o1 a& l1 {
  49.     // }
    - ?% J; f2 J6 j
  50.     // echo $id;
复制代码
) D  Q$ J; g/ t9 F9 a3 {

1 h5 W$ i- f# a; K6 w: L
抢券活动实例:
  1. public function envelopeSnatching(){
    . w+ d$ B) C. @+ ~
  2.         $lingqu = $_POST['type'];- ]4 u) I( ]9 g  Q8 O6 E+ c
  3.         $uid=session('u_id');//用户id
      k" r& z3 v/ [* P( C( t
  4.         if(!$uid){
    ; _: @: h) M: k- M0 k. J
  5.             $data['msg']='您没登录,请先登录!';
    ' B7 {, b; R7 j' T
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    - c+ X8 u( c$ m. a9 c
  7.             $data['msg']='不在活动时间内!';( z3 b9 w0 f3 C; q' T' J
  8.         }else{
    2 R6 a4 ?& q; T( L
  9.             $hours=date('H');//当前小时数5 ~" J. H! |+ e( [& C3 l
  10.             if($hours > '09' || $hours > '17'){' l) t0 ]/ ]# R  d
  11. - N) b" q) N; s8 [
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    # }* Y# ~) ]) K: q
  13.                     if($lingqu == 1){1 _1 S& |, j1 k/ t# b' X- Q8 I
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    % e, |8 \6 B( u$ C: E/ U% U
  15.                         if($hours > '09'){
    , n) f- w# k7 s+ |+ l4 k& ]
  16.                             $num=mt_rand(25,28);//优惠券金额
    ( y0 X. E3 y" h6 h3 g
  17.                             $id=1;
    ( b8 D' L2 q7 [; `0 f& b
  18.                         }% D# e1 Y; W! D! a
  19.                     }else if($lingqu == 2){) S6 Z! W* A- u$ D  k6 f
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();# u) o6 l% D6 p* v
  21.                         if($hours > '17'){9 u/ j( y& r" y4 ?6 @
  22.                             $num=mt_rand(50,55);//优惠券金额
    5 @$ r8 p" O2 [  V# E. V. |
  23.                             $id=2;
    7 g3 v7 ^7 ], ]: g: @+ r
  24.                         }, ?: W! l5 T9 @- z0 Y8 q
  25.                     }
      {5 O4 q  t& V0 u" V. d* t
  26.                     if(!$id){% V9 e: P- P5 Q. A
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    2 D/ A4 K" O  Q7 _$ l, a; }
  28.                     }else{
    * l6 f' b: i, U# p
  29.                         if($is_lingqu){
    / d. p, ?+ S+ N0 u4 I% ^
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';! W7 z; p5 t- I5 x3 n0 d
  31.                         }else{
    ; @0 h/ G3 A& ]8 ~( a
  32.                             //锁表
    2 Q) [& N# \& ~: R  d
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    5 a1 E, i0 f" M0 W6 K2 d
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    % ^! g( @" q6 p; v: ^3 b0 e" y
  35.                             if($active > 0){. `- A) S4 Q2 y* U
  36.                                 //开启事务
    4 t8 a2 r- U& Y# t" J1 A
  37.                                 M()->execute('start transaction');
    $ N1 d: p8 j: A
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    ) M, {6 x8 f1 E
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    7 A9 }. c" I! ~  ^7 \8 i; r
  40.                                 $members_preferential    =    M('members_preferential');
    4 ]$ i/ ~: W' T% t  |; \. C* ~% p
  41.                                 //对应投资金额,/ T1 q* v. \! ^2 `- @  \; C7 o
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));# A3 f, X) F8 e5 E
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');. P  `7 X5 J9 I" n
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间) P5 q5 w& K  j& Y8 J9 e
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
      a2 b0 P' x. x6 C
  46.                                 if($save && $add && $add2){
    . W; X3 i0 W1 D+ x2 t& m/ P7 |2 C2 I
  47.                                     //事务提交
    ; m" y9 q" D5 H3 Y. E# Z
  48.                                     M()->execute('commit');
    / p* |' l3 M0 R: n0 t; t
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    # Q' Q! l) c3 z8 _2 L% q* K) m
  50.                                 }else{" _4 p( |' ^0 p* t& A
  51.                                     //回滚
    * `) ^& I# I+ ], m
  52.                                     M()->execute('rollback');
    . g4 s  f2 w6 h" p  ^( ?7 r
  53.                                     $data['msg']='未知错误!';
    - D& Z& |/ x  F$ R: [
  54.                                 }
    & q  V" Q% c" ?; o
  55.                             }else{
    ! w5 Q/ Z5 z7 \( G3 N# o- Q' e
  56.                                 $data['msg']='红包已领完,你来晚了!';
    ) P( j& f, N8 c
  57.                             }
    ) \: v9 n$ B% h+ d& J) `+ p
  58.                             M()->execute('UNLOCK TABLES');% ?& D* B' s, F" P
  59.                         }; j' V! N5 f" M# |. {) q. t7 Y- m
  60.                     }
    9 ~' S- R: G1 ?: G# z9 K+ z
  61.                 }else{5 ^4 n( B. L: Y/ }
  62.                     $data['msg']='非法操作!';
    ) {8 t- Z  S. h1 _3 J7 [, M
  63.                 }9 x7 {: D# {: o# X
  64.             }else{
    ) e6 R9 c0 h, T, I# F/ t9 \
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ' B8 u5 u! v* {
  66.             }& m# C# y5 N! B& i1 v3 ^- P
  67.         }
    ) v7 F5 w% H& h; h
  68.         exit(json_encode($data));% }! `- p9 ~- `7 z# ]
  69.     }
复制代码
# d  W; u" {$ P+ o
, y( w4 }4 _- e5 d. ^" y# V: i( f
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 16:09 , Processed in 0.074748 second(s), 20 queries .

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