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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

1 G+ L/ Q* A$ g3 I  z* ]# V
Mysql中的锁语法:" j! B8 a3 j% h
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
* T+ W( O9 j/ ]5 c7 x0 W! aUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表  b! ~) l" x" q$ M5 f1 ?  h
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞2 a( G& b& r1 g' M% }( E0 J
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
( f& r, Q. o1 l文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
8 S7 g' O* n% v; ]测试时,有个文件就行,叫什么名无所谓
总结:1 X+ L8 d9 q3 b0 o- k  I
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
9 X  G9 N: r! t/ c1. 高并发下单时,减库存量时要加锁
3 x$ D+ m8 Y& K/ Q1 m; Y2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    * X: U( N% b( g$ }0 r' r% C! j9 E
  2.     模拟秒杀活动-- 商品100件
    ; W# J8 [, ^+ m! k/ N/ y
  3.     CREATE TABLE ta
    8 u  r/ d! h7 w/ L5 U  J
  4.     (
      t. ?( @' b9 c0 `) b& `
  5.         id int comment '模拟100件活动商品的数量'0 c1 \* S* ]% l9 i0 i( ~
  6.     );7 o7 n9 C. o% V4 e% ~5 ?
  7.     INSERT INTO ta VALUES(100);
    % q- t( }# _" f4 k$ v
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    & d5 _! ~+ o" R% v9 b
  9.      */
    * N; W4 I% w  X; E% b+ F
  10.     ! Z! m' ^! \9 m, U' u7 F
  11.     // 关闭错误报告2 B- w! \8 C( e: X# F8 ?
  12.      error_reporting(0); ( n0 X6 L% @2 {9 @4 Y

  13. 5 n* \$ R6 R2 w
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址  X+ k9 o4 p+ r7 {" f
  15.     $dbuser = 'root';            // mysql用户名! ^# C. ~2 S# V& u
  16.     $dbpass = 'root';          // mysql用户名密码
    2 B6 {8 r9 a9 C( T9 X! D
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    , ]0 e! M4 c, G) O9 O! _( P
  18.     if(! $conn )
    & F$ N6 b. _" e2 Q8 j; \6 {! b
  19.     {
    & N8 K1 U6 X& o: O1 U5 N8 R2 Z# Z% S
  20.         die('连接失败: ' . mysqli_error($conn));' ^; p, |8 c+ y* ?; o! |& ]  S6 `
  21.     }4 y* Z, E6 r; C! T$ g
  22.     // 设置编码,防止中文乱码. a- q1 T/ I% @! c1 d
  23.     mysqli_query($conn , "set names utf8");
    " W3 v0 y% L7 e! w
  24.     mysqli_select_db( $conn, 'temp' );
    : a2 T( ]4 h& `# y5 I- l: {/ F
  25. " J) m0 ^% O/ U/ {# _. X" N
  26.     # mysql 锁
    & ]; I" H) p% o' O7 ~
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ! p# X3 _/ u2 w$ z- Z
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); - V- H) `, M5 f4 E4 z* o
  29.     $id = mysqli_result($rs, 0, 0); . ]/ g2 G- s' p
  30.     if($id > 0)
    ; K; L" U9 s: N+ b' l7 M, H: H- ]
  31.     { 6 M- a; A7 T0 S4 x4 ]. W( x
  32.         --$id; 0 q! _5 l6 H6 Q' [1 n
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    # g/ O. Z; K; `0 f4 o
  34.     } 2 ?) E9 A6 ^+ Z* ?1 M# }. I
  35. # G2 G# v. I( \: Q* [
  36.     # mysql 解锁 8 L; t: ~6 n- [% R2 Y$ w
  37.     mysqli_query($conn , 'UNLOCK TABLES');2 J* v" o/ R2 b5 d. A" e
  38.     //查询解锁后的id值$ x! }$ S, e0 M, [. b( d
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    : {  \, f. G* ?( Z
  40.     // while($row = mysqli_fetch_assoc($res))3 ]/ F  I1 _. Q+ P. `& o
  41.     // {2 I7 [) |7 A& Q0 x7 K* k& ?
  42.     //     $id = $row['id'];4 c" r/ }- ~$ e
  43.     // }
    6 _8 U6 j8 `% R) [) ?, X  [; ~* X. O
  44.     // echo $id;
复制代码

; D; \* I" A% N( W0 M, ]% O% V' i, D" P/ \+ G0 [- [6 ?
6 @% o0 c; p* S( }
PHP文件锁示例:
  1. /*
      d. y4 q- o1 b7 `8 g
  2.     模拟秒杀活动-- 商品100件3 `6 l0 x% O' m# ~# D
  3.     CREATE TABLE ta
    + m: I; G1 P: H5 v" b* M& c
  4.     (: G- ?. q* a: E% o: d
  5.         id int comment '模拟100件活动商品的数量'1 @. N/ C/ z: Q2 Q2 U+ v$ O
  6.     );4 u; M2 l8 o, x+ ?, T7 X7 a6 m9 i
  7.     INSERT INTO ta VALUES(100);
    ) d7 u' c) @7 Q  I) s' d
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件1 ~8 t0 o- j7 D' R4 ~2 c& V
  9.      */ + g# C' ^- e8 I4 d! R/ p  x
  10.    
    # j: |! m( f% T2 Z
  11.     // 关闭错误报告1 E$ r: W7 y4 u8 [% k+ }
  12.      error_reporting(0); ' R: `: I6 S5 |) E

  13. / ~6 r( ^) g5 N3 K
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    / r4 Z7 I  P- _5 `
  15.     $dbuser = 'root';            // mysql用户名# d+ q3 p5 U1 R. R; c
  16.     $dbpass = 'root';          // mysql用户名密码
    ; H+ ]9 T3 I( G- v2 W0 y' S+ ?+ {& @
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    $ ~) g4 F/ }' U2 L5 Q. R. f
  18.     if(! $conn )
    / x+ [  A% I& t; s9 v$ y# q
  19.     {
    - q% q- g1 `, _: j) }
  20.         die('连接失败: ' . mysqli_error($conn));2 x3 P# [3 e7 b# U3 C
  21.     }% S% H% ]2 q, m6 l$ v
  22.     // 设置编码,防止中文乱码$ Y9 ^) s  G+ K8 [  G4 V: C
  23.     mysqli_query($conn , "set names utf8");8 J$ S: s# m* c- y
  24.     mysqli_select_db( $conn, 'temp' );
    ! A3 `" K7 {* Z& w; k' i

  25. 1 t5 n7 g5 n( T9 q! g' Y9 z9 s' d
  26.     # php中的文件锁 $ ~1 b# X' D% Z& Z5 J' v+ Z
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 4 Q* M7 @6 e7 {, u7 S0 N
  28.     flock($fp, LOCK_EX);// 排他锁 ) i2 y# U( X  h
  29. - ]) ^, M5 I3 d/ |
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    ; r/ i& @+ w% i
  31.     while($row = mysqli_fetch_assoc($retval)), c0 K& h+ u  t( V9 i- _. C1 Y
  32.     {( X" i+ ~. c# c( n& [
  33.         $id =  $row['id'];, u; m# N3 l9 T9 v4 {. B: x
  34.     }
    2 @0 [* b' r* G( E5 D
  35.     5 ?$ ^" _% F6 ]  `9 m/ c
  36.     if($id > 0)
    * {+ y+ Q& c. w
  37.     { 2 b# \& K7 o; d! P1 I. r$ j
  38.         --$id;
    ' U: ?3 P/ f3 v2 S8 M8 s
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 0 _4 z3 u: r0 m5 b" J, L( X' [% N
  40.     } $ e1 K3 u8 E8 R2 j
  41.     # php的文件锁,释放锁 " G3 X9 M$ k5 I5 Y
  42.     flock($fp, LOCK_UN);   I, e8 F# @; k- p
  43.     fclose($fp);  t- e, j* H  J. [

  44. ' C5 ~6 Q  G: e+ |9 H! u
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');$ ^$ O# e% {2 `7 f* j
  46.     // while($row = mysqli_fetch_assoc($res))
    3 J+ J) a, E) [5 i/ P/ A
  47.     // {  [7 T. @7 ^; n
  48.     //     $id = $row['id'];1 m- {0 j) Y  h1 V  K) |
  49.     // }
    # n% M% x+ H5 g# U
  50.     // echo $id;
复制代码
4 Z0 a8 k* L3 m: _; ^5 ]8 H6 a

- M5 X9 [6 {+ Z+ `& L$ Q9 I' d2 J
抢券活动实例:
  1. public function envelopeSnatching(){! K) [) b1 G8 W7 t2 S$ B2 f5 A; O
  2.         $lingqu = $_POST['type'];
    7 F; ?8 |) f# Z+ I$ U
  3.         $uid=session('u_id');//用户id
    9 P  @1 V9 E! e: Z+ {
  4.         if(!$uid){
    : L% ?+ X% v% D/ T0 k* M
  5.             $data['msg']='您没登录,请先登录!';
    2 h4 k/ @: [; {" ~1 @9 W! ~' ^
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    % Q9 O  ?; u! o0 ?, x
  7.             $data['msg']='不在活动时间内!';8 s2 y2 @& \% e  @1 j0 n- z
  8.         }else{. R; V) t9 U% J7 G' J! E7 g* ]
  9.             $hours=date('H');//当前小时数6 i6 V1 |# T. \' y, L
  10.             if($hours > '09' || $hours > '17'){
    9 B3 ^1 K# Z" {) B$ `# a# ^

  11. ; s  W, _( z6 H# E' @
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的  N2 Z4 I' [& g
  13.                     if($lingqu == 1){8 a: n* l. E! p$ U
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过2 a, f% R) t# N$ m  o: n
  15.                         if($hours > '09'){
    : V" _) z" V0 M  ^
  16.                             $num=mt_rand(25,28);//优惠券金额% O: T  K, H! P6 X) e; `
  17.                             $id=1;
    3 V5 g3 s% M% V1 N* W) K5 L
  18.                         }: G8 Z. C% n) ?  x9 C; q5 I) F' M& z
  19.                     }else if($lingqu == 2){
    5 J0 b/ v0 t. ^  ^0 f
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();/ Y! v& |- A* n# p; e/ ^: f4 b
  21.                         if($hours > '17'){( P& N2 m4 ^& O; i# K- O" H# F* T
  22.                             $num=mt_rand(50,55);//优惠券金额- h% v0 }( [2 j4 D) b( S
  23.                             $id=2;  [! n. a+ r( t* p8 ]: ]9 I
  24.                         }
    . Q2 A$ @/ j0 d
  25.                     }
    . f# m' s6 h9 W$ y4 K! V4 `- @
  26.                     if(!$id){
    * B$ C. D6 o% N3 c9 Z% ]
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    ' F" C5 m  g0 G. s6 I
  28.                     }else{, l1 a5 @' U* m' C3 g
  29.                         if($is_lingqu){/ I0 y* c9 A. z% r
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';. P6 m" n- a( y; c5 J- y
  31.                         }else{' y; v6 T- ^: H, K3 G: M$ s3 A
  32.                             //锁表
    7 F* E" t" O+ @% g- k. S; n1 z
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    / Q6 u0 i( w( A8 W* C5 `- k9 K% X! x
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();  R6 C% S: ~5 B4 i5 X/ t& B$ _
  35.                             if($active > 0){5 A& j! P$ q, F" r
  36.                                 //开启事务
    # u+ H7 V: ]4 J
  37.                                 M()->execute('start transaction');
    6 Y; a0 [- t2 I7 A
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));7 W4 B, ^0 e0 o0 a; ^, _
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    / X' K, T+ Z- e# Q" c
  40.                                 $members_preferential    =    M('members_preferential');
    ( X& ?- s9 P6 V  I
  41.                                 //对应投资金额,  e& o3 p( u9 X5 i* J6 J. N
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));0 y8 F8 D  Y2 L
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');: N& U9 `$ n; K7 b
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    ; H4 T( J. v4 B
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    . `% u: a- v* z4 T; X- U( \
  46.                                 if($save && $add && $add2){
    3 b1 ]' a/ k) `1 C0 ]
  47.                                     //事务提交5 G! }$ D! r7 a8 N. l9 B
  48.                                     M()->execute('commit');
    / S+ ]/ @3 c: B
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    3 T: \* p# i9 a' ^  _- d) ~
  50.                                 }else{
    ; P) k9 A# C* }; R7 P2 Y# F' H+ j
  51.                                     //回滚
    3 _& [. W3 y) A+ w( f% b
  52.                                     M()->execute('rollback');
    8 v! r9 ~7 p# j$ [; b. u
  53.                                     $data['msg']='未知错误!';
    * J9 \4 k) \% q. M5 C( Y
  54.                                 }  n0 o( Q# n3 {. f
  55.                             }else{
    8 ?0 a7 d5 T& m2 x, f
  56.                                 $data['msg']='红包已领完,你来晚了!';" T7 C; y. a+ r  S" C
  57.                             }7 O; U- Y( N! m* }' j' R; f; L
  58.                             M()->execute('UNLOCK TABLES');
      T. b: e8 x; n2 H4 A1 @
  59.                         }& `3 V" z) G& m+ ^- o4 f% [6 ^
  60.                     }
    , L2 f* l; R! ~* _1 A2 c
  61.                 }else{: u; \  r* P* u0 O- ]
  62.                     $data['msg']='非法操作!';/ q0 u+ P1 u. }0 d/ p; |
  63.                 }
    1 n4 B' ?$ V3 s
  64.             }else{
    5 Q" e" U8 f2 ?! M7 i6 Y. l. V
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    , v' e* c7 H9 T6 w
  66.             }
    8 s  Q  F# t1 b  K* `1 }7 w/ r
  67.         }
    0 k5 I3 Z7 ], s* r& O  a$ K2 B/ M
  68.         exit(json_encode($data));
    " k. x! H( N6 J9 f5 `
  69.     }
复制代码
$ n( w! s# a* r/ [( K  n9 Y$ R

8 g5 f: h  h8 @$ Q4 o
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 11:13 , Processed in 0.158819 second(s), 19 queries .

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