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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 5736|回复: 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://请求的脚本
复制代码
8 \; B9 d+ a% U6 S: H3 G" f1 n- z
Mysql中的锁语法:0 n# E3 W1 r8 K* X+ e, a# v
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
, p5 [4 B  c& c0 L. i  }$ E9 S0 JUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
7 k9 `" M5 P+ S2 {Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞1 z/ g; N( q' n2 c2 R% Q  @" [
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :! A; N6 q5 m5 m- @' n7 O4 f  X
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。/ z3 e3 I. w& y) w7 m
测试时,有个文件就行,叫什么名无所谓
总结:
- J- o0 ^8 q8 _, i1 O& e项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
- A6 w$ W1 z% M( \& E4 q1. 高并发下单时,减库存量时要加锁
# m# w6 U$ z6 z; m2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    6 R; @! k) Y* S  O8 Y+ `
  2.     模拟秒杀活动-- 商品100件# K5 d/ ~( ^& s9 i. s5 ?
  3.     CREATE TABLE ta
    # r1 @. |7 x, [$ e
  4.     (
      `# o4 ~$ j9 V. {% O) t* o
  5.         id int comment '模拟100件活动商品的数量'
    + |% U' p2 s1 _, a8 K9 O! G$ A& J  J
  6.     );
    7 ?# ]0 G4 ?/ k8 t( y, M
  7.     INSERT INTO ta VALUES(100);
    5 L7 J5 M0 K* `
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    % Q+ h, S9 b  A! R2 W* Z1 N
  9.      */ 2 _. t+ L( p9 @+ r/ G* h
  10.    
    + m/ f: h) ?3 r
  11.     // 关闭错误报告
    ) `% W  o' U4 i* v1 ^1 C+ E
  12.      error_reporting(0); # v1 S2 C: |* p- X, w
  13. . S( j" z4 b& n2 n
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    / y3 M# ~# D9 V5 d6 A. W) v
  15.     $dbuser = 'root';            // mysql用户名
    ) F2 P1 U/ E7 j% k2 _" r" d- @, c
  16.     $dbpass = 'root';          // mysql用户名密码
    8 j' K+ i. x9 U/ U/ `, {
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    , t5 p9 _( N+ p- \
  18.     if(! $conn )
    4 _+ L7 j) Y3 j' j
  19.     {: j- k' [$ i3 O& ]& C* q5 |% E5 U
  20.         die('连接失败: ' . mysqli_error($conn));
    7 }6 |$ b$ `% p7 {5 l" I9 E7 e
  21.     }
    : z- k  N( z# Q
  22.     // 设置编码,防止中文乱码% e8 d2 _- i, A  q/ [+ I- N
  23.     mysqli_query($conn , "set names utf8");1 _4 v: V- Y3 p
  24.     mysqli_select_db( $conn, 'temp' );
    $ s* k9 J% {  ^2 l% p0 w8 x$ {
  25. 4 C, f2 ^* b4 H/ \" ?+ o& K7 m
  26.     # mysql 锁 ) o& h; w3 u7 S4 d3 P1 s  E/ f
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 5 ~- t- U: \! N7 {$ |: t# R3 ^
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    7 M. M' o& U. ^: }: C) n
  29.     $id = mysqli_result($rs, 0, 0);
    8 G8 J! q' ]2 c" i7 R; j
  30.     if($id > 0) 7 b( {( j0 h6 c/ M# o8 R2 Q
  31.     {
    $ u: L+ y3 ?0 ?4 n) ~
  32.         --$id;
    0 o9 {: Y- ~# K
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); " W7 g& W6 r5 B- Y# j8 }7 W
  34.     }
    $ P% k$ X, {1 K, W& O8 z

  35.   D! I# w; V; n) T
  36.     # mysql 解锁 ( E1 E; ]1 ~  Z! E! B) {' N
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    + o9 y9 y$ P* A6 j% N$ G4 A) q
  38.     //查询解锁后的id值
    1 }; s( u& j* |$ {& m7 M
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');; ~+ x1 [" L+ v% L  M+ B
  40.     // while($row = mysqli_fetch_assoc($res))2 H1 O9 {# u# u
  41.     // {
    1 C& ]% b8 b; `  `
  42.     //     $id = $row['id'];
    + ]9 J# |1 R, I: y
  43.     // }) l1 \- t, Q/ ]9 I3 s) g+ v
  44.     // echo $id;
复制代码

+ H3 K9 B6 S5 E- Y9 B6 }& H) R: p! L" C; L- `0 M

: B/ z8 P. F4 X* u  r
PHP文件锁示例:
  1. /*+ s4 C$ N& V. f  Q- O, H
  2.     模拟秒杀活动-- 商品100件
      v4 j% d# Q& Y- z
  3.     CREATE TABLE ta. a4 o% E$ U+ v0 D$ L6 R
  4.     (* K$ V- @. M; z& g) h: _
  5.         id int comment '模拟100件活动商品的数量'
    ; }: _$ n/ I  n2 x5 K: X
  6.     );
    3 P4 f' o1 s  n; T
  7.     INSERT INTO ta VALUES(100);0 z5 `$ }6 Y2 k% X2 P
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件* M3 `( x+ u6 }
  9.      */
    ' n# Q5 g9 g' @$ Z! n7 Q
  10.       O; L+ l% s3 J, j% a. L' _  ~' o
  11.     // 关闭错误报告: k$ Y' J* Q+ }4 J
  12.      error_reporting(0); 5 V% ~) U$ [) p- ^% ?0 K8 D8 ?" W

  13. 7 p& T: w/ i7 l7 S. l
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    , T, T: [0 ~$ }+ q( R
  15.     $dbuser = 'root';            // mysql用户名2 E" j$ [/ O  w+ U0 }0 K
  16.     $dbpass = 'root';          // mysql用户名密码
    # _8 J+ a  k, G1 ^2 s
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);) a& f7 ^; F. h1 V( G0 T5 _& |
  18.     if(! $conn )
    / U% I" j- F6 x4 |6 g1 g
  19.     {
    9 V% f* O2 q! ]8 P- {  D. P
  20.         die('连接失败: ' . mysqli_error($conn));- c4 w$ B3 g4 Y& E1 v& L2 R* }
  21.     }2 G- L9 v' k8 f* W
  22.     // 设置编码,防止中文乱码
    : [4 e0 G- b) q/ I
  23.     mysqli_query($conn , "set names utf8");
    ) h8 u5 v- V7 d1 j6 S: R  ]
  24.     mysqli_select_db( $conn, 'temp' ); ; a: }* N$ A2 W% s
  25. ( p9 x* r+ I( j" E) S
  26.     # php中的文件锁 " C2 A7 H0 l$ _
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    : B" d. g1 s. B$ I
  28.     flock($fp, LOCK_EX);// 排他锁
    - W6 ]) i( O2 ~) J" g) w

  29. , r( i! |3 V, G
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 0 x% ]8 L% o/ {. J/ A8 @
  31.     while($row = mysqli_fetch_assoc($retval))
    & F5 ~# U: W( P- U
  32.     {
    : u9 q" L, X* z: e& `! k
  33.         $id =  $row['id'];
    9 N; K- j/ n! ^# V( N6 e, m
  34.     }
    3 n. N+ _/ V$ @, F4 @) R6 N( @' c2 {
  35.    
    7 k! V3 y. K  g
  36.     if($id > 0)
    2 U0 w0 `3 o" _
  37.     {
    0 M$ Q: n4 e+ `; ~5 l4 D9 V  d: ~; N6 G
  38.         --$id; 0 l7 y/ u! @  a4 O8 t
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
      _, Y" K7 B6 P2 H& u9 |0 z3 g
  40.     }
    # K3 J* e  `  e
  41.     # php的文件锁,释放锁
    " i1 A5 l" d( G6 x, v1 I" |
  42.     flock($fp, LOCK_UN);
    : n/ T/ m8 e8 F
  43.     fclose($fp);
    % F. X5 z2 V* j3 y* c2 N0 f" i) N( g

  44. ! m% g& e" p1 N8 A) O8 v0 d! v
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');% y+ _" C) Q& w
  46.     // while($row = mysqli_fetch_assoc($res))
    # Q6 [8 d; B7 O) y
  47.     // {! y: Q. U' T- u+ y3 i# |! S
  48.     //     $id = $row['id'];
    , T2 \4 O9 t3 B& Q% S; z' d
  49.     // }
    9 `1 `: U! i8 Y  L* \5 d
  50.     // echo $id;
复制代码
4 B3 B- d7 P( C" y
8 P* s6 q+ r- ~
抢券活动实例:
  1. public function envelopeSnatching(){8 P" C$ i5 u2 I/ o& S4 o$ S" K- ~/ z
  2.         $lingqu = $_POST['type'];+ C& t1 d& n- q# \3 u5 w/ j: G9 c
  3.         $uid=session('u_id');//用户id- G! j# r% g% M2 t
  4.         if(!$uid){
    2 V! N1 @: o- t/ j1 R
  5.             $data['msg']='您没登录,请先登录!';. }# E/ _2 q" f$ `5 ^$ p
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    * I, A8 p9 o7 E( W. i
  7.             $data['msg']='不在活动时间内!';/ Z7 X7 O1 {. G. v4 T  l* t
  8.         }else{1 p5 [% c7 |: J+ V! O! }
  9.             $hours=date('H');//当前小时数
    6 e$ B0 {1 r0 g& F5 a" h
  10.             if($hours > '09' || $hours > '17'){
    3 \2 I4 X4 b2 J$ n
  11. 6 N1 h: b/ Z% Y* n8 b" \
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的" n* a7 A% |5 [) K  M
  13.                     if($lingqu == 1){
      o, _8 C: S1 r# i3 N  W& K
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    ! |/ Q& I2 e% y1 A& ]
  15.                         if($hours > '09'){
    . v! A# s6 {# ^6 `8 a& N
  16.                             $num=mt_rand(25,28);//优惠券金额
    6 N" B  K+ {* g% d' O( e% i$ ?
  17.                             $id=1;
    - O; |4 _. e* I1 C% J, `
  18.                         }
    " a# h' E2 E1 P3 K! s. F
  19.                     }else if($lingqu == 2){
    ( N& S% N( l: A6 }# n* R4 X9 \
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();. p0 \$ X! l7 O, z0 Z6 n; {! u
  21.                         if($hours > '17'){- D) X7 x# _# g, z5 i' h
  22.                             $num=mt_rand(50,55);//优惠券金额
    / d8 {  b3 G3 B, a% e
  23.                             $id=2;
    / h; R5 D) ]) B1 o. v- F3 g
  24.                         }% m# n: d! P4 [" j" }
  25.                     }! q, R- w+ }4 f  K1 S0 \" d
  26.                     if(!$id){  [, i3 R/ j  x3 i" d, e( G$ q5 O: I
  27.                         $data['msg']='时间还没到,晚点再来吧。';# O/ h$ F) [! b# w/ a$ u- Y
  28.                     }else{
    0 ^+ u6 Q& B  }4 j. g# s9 e
  29.                         if($is_lingqu){$ ~2 I8 `: j! h  o( v4 _; i  B' M
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';5 g9 `6 ]6 I9 X% v3 m* Q
  31.                         }else{" Y& Q' _9 q+ O2 T7 x& x5 ~3 n. _! u
  32.                             //锁表. w, c% Q! }% g) N5 N
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');' m0 H3 \# p- s- U+ K) J  S! {
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    " v5 v' v# n- e# g( f
  35.                             if($active > 0){. k9 ~& i9 |: C3 k1 L, ~7 Z
  36.                                 //开启事务2 `0 z, c0 J. O
  37.                                 M()->execute('start transaction');5 X3 a$ _4 d# y" r
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));( B+ b: C! _1 Z0 Z; m+ L& z
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));, ~' v5 R: y' v# Z
  40.                                 $members_preferential    =    M('members_preferential');# _! o" E/ E+ ]/ t5 H  I/ i
  41.                                 //对应投资金额,
    % G( n% K0 r0 i8 ]: ]% v4 j% K
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    , E* S* x6 m3 a+ `" X
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    / w) i* t: w, K
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间6 ?7 {* ^3 T2 u* J
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券5 m9 D. H% @# j; t' W; S7 p
  46.                                 if($save && $add && $add2){" O1 C( U' S! q
  47.                                     //事务提交
    & g4 K3 k9 ]# f
  48.                                     M()->execute('commit');: G5 r2 U# O& X/ y+ d# k
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';3 Y) F2 s! u$ F. j. F
  50.                                 }else{. T8 Z# n0 }) S( }5 D
  51.                                     //回滚
    9 _$ Z9 E8 }! w0 g
  52.                                     M()->execute('rollback');
    ! g) _- U8 A# g  a* o4 h7 y* _/ h6 @
  53.                                     $data['msg']='未知错误!';
    $ [* B# j- }. T' Q3 y2 ]: i$ r
  54.                                 }( V, _8 X$ ]- M* u
  55.                             }else{1 Z/ v( O) L0 @: B8 ?) a. T
  56.                                 $data['msg']='红包已领完,你来晚了!';
    & S% I& r( |. o. T2 E" ]6 r
  57.                             }- n' C% S6 u. e0 A# o# b( T/ K
  58.                             M()->execute('UNLOCK TABLES');
    ; j7 H/ |4 m8 @0 _: ^( B; Z, M
  59.                         }
    7 o2 Y" B: Q; X7 x
  60.                     }. t8 t5 R! Y  G) C4 i9 }) v9 K+ l
  61.                 }else{
    # N# z" Q, T& d
  62.                     $data['msg']='非法操作!';
    " K1 l! s2 X9 l9 l. v
  63.                 }. D$ x/ l2 y& ?+ T
  64.             }else{
    9 b) c( Q: O8 `* I+ i" `
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';2 P7 P" b5 u3 `; J9 P; @
  66.             }
    : D; q/ O: U* m# Z
  67.         }
    8 Z: }3 \0 Q3 c1 L3 X& \& H, K9 d
  68.         exit(json_encode($data));- v, i$ [" w9 E1 V- _' s: [) y
  69.     }
复制代码

* E& ?7 f5 z4 L& C9 p* `: w* R
0 z6 j3 Q  {& i$ V% g0 y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 12:02 , Processed in 0.109093 second(s), 20 queries .

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