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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

) b: j# Q/ B' D6 Q7 A
Mysql中的锁语法:8 t1 W3 O, \9 I- A
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
, L: b$ A/ G( m( H4 ]UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表0 w/ H, l, j# b( b, P% H
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞! w! j. U9 o% c: E
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
. _: X4 y0 \+ Z* ]. G9 C( N( S' ^0 X文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
/ K: @+ G3 o* V, p测试时,有个文件就行,叫什么名无所谓
总结:& }% ~; C1 G. p% G" y
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
, y- A+ D. m/ o7 C: a- ]* n1 F- N1. 高并发下单时,减库存量时要加锁
% b2 o: ~2 u' n! ]* ~8 ?" ^2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*3 S# m0 t, v) S0 C
  2.     模拟秒杀活动-- 商品100件* n! h6 ~; R  j: i0 |
  3.     CREATE TABLE ta
    / u- N. ^) ?( O8 q7 t$ z$ C
  4.     (/ b! K+ p! O7 o
  5.         id int comment '模拟100件活动商品的数量'
    - N1 k* r8 _2 ]- v4 `
  6.     );, F$ n+ j$ q, C9 `7 p: [
  7.     INSERT INTO ta VALUES(100);* c/ S5 W4 j" ^8 x0 i9 e9 E
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    0 L& s+ t; K8 B6 _. b
  9.      */
    9 E4 L. A% C1 y+ f; K( i) s
  10.    
    7 @0 f! x% x* i' l$ q" P) m+ `; x1 j
  11.     // 关闭错误报告
    # }) u# l5 }. p$ H+ _
  12.      error_reporting(0); * ?* @- E* @4 _, Y; _
  13. ! V$ N& S2 x" K% j! _& S% l
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址# }; T1 i7 O- t- _2 G& I$ L6 f) B
  15.     $dbuser = 'root';            // mysql用户名
    ' |0 }; ?& b) `9 e- o" L, ~
  16.     $dbpass = 'root';          // mysql用户名密码% J0 K6 c3 r% k7 Z+ c
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ' [0 ^/ {( q' @7 g
  18.     if(! $conn )
    ( V9 g1 g( V2 W. s3 F0 g1 ?
  19.     {
    & B5 {" U3 _) F
  20.         die('连接失败: ' . mysqli_error($conn));
    : M+ z7 P$ o+ Y/ Z- b) S1 [7 q2 K
  21.     }- I: a( F0 e' V  ?* \  L
  22.     // 设置编码,防止中文乱码
    1 ^$ s# S  N# Q! X6 r
  23.     mysqli_query($conn , "set names utf8");( O/ f, n+ i  R
  24.     mysqli_select_db( $conn, 'temp' );
    9 L% _& J8 ^. `% f1 Q+ Y

  25. 6 o/ Q* c4 l  v: X6 E
  26.     # mysql 锁
    ; k( J; R2 t% F8 J! |  M
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    0 g* K4 M. r2 o9 M
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 8 K4 r! [! I2 a7 \7 C9 A, p
  29.     $id = mysqli_result($rs, 0, 0);
    8 i, J' F; t& H* p, `- J
  30.     if($id > 0)
    - i. e% C" ?# |2 X
  31.     { ) g4 I) ]. Q. T9 U- _% b
  32.         --$id; 4 ^: L) z0 W: V6 I+ D
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    8 R/ O) f3 Q% Q- t5 \( C8 b
  34.     } 3 q) g. l. s' k  v5 U4 L: B
  35. ) v8 `, i( V* n8 t% @7 ?, O
  36.     # mysql 解锁 8 l5 n4 G8 a2 k4 R2 A- ~" c; c
  37.     mysqli_query($conn , 'UNLOCK TABLES');; l2 K% N8 u6 A7 j; a* `$ v
  38.     //查询解锁后的id值
    5 C  m, M$ v( ?7 r& @
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');1 X( \7 J" j# N; h5 H7 v  n' {
  40.     // while($row = mysqli_fetch_assoc($res))! ^7 C) m0 k2 r) P0 i  ?, [; H$ P
  41.     // {
    ' l9 s1 y. b) _  R7 `
  42.     //     $id = $row['id'];
    3 S8 C1 w3 O* T' a
  43.     // }
    / _8 A, |& M; v* E6 T# h( c
  44.     // echo $id;
复制代码

( b' b+ }9 g/ B* ?
4 ?, J5 w8 m4 w

2 [8 a* J* P5 Y0 q) Y5 V- Y
PHP文件锁示例:
  1. /*
    + U" ~6 O1 k8 u# T" ^: G
  2.     模拟秒杀活动-- 商品100件
    % o/ x6 q% N7 u% ?
  3.     CREATE TABLE ta
    8 ?: X( h0 C  ~8 M" z4 y! E
  4.     (# c9 O& c. t5 K  l
  5.         id int comment '模拟100件活动商品的数量'+ n) v) S# P( M9 B
  6.     );
    : l  q1 [1 K" s: W( T! Q" [
  7.     INSERT INTO ta VALUES(100);& C+ R; @* V+ V2 @8 l
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ( V' z3 w- `6 n5 i- T
  9.      */ $ w  `7 e3 t) a) g* F# l) f& Z
  10.    
    5 }- ~. @5 Z  x* \
  11.     // 关闭错误报告
    ) d; [; F$ V  i  x  h0 ]2 q2 @
  12.      error_reporting(0); " i; s3 }; i- k1 x

  13. , K. R% _) g# f* n- P3 F7 s- B
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址, A) }. |" `" S, s  x2 {
  15.     $dbuser = 'root';            // mysql用户名
    ' ?* N8 k& M2 D8 W8 @! }
  16.     $dbpass = 'root';          // mysql用户名密码  ?: A' C- i' u6 m% t
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    5 G; r+ O5 P( j
  18.     if(! $conn )' O- s) f& \+ C' {
  19.     {
    ) l9 G1 M3 F. Y; r0 ^; i- ]* e
  20.         die('连接失败: ' . mysqli_error($conn));
    $ G6 x8 t4 s7 H. h  `
  21.     }
    / s& x! X% {) f. K+ A! O# [
  22.     // 设置编码,防止中文乱码
    7 d* H- Q3 q1 F* j: D" j
  23.     mysqli_query($conn , "set names utf8");
    ( Q0 r# h7 M& U3 E6 K( F
  24.     mysqli_select_db( $conn, 'temp' );
    . q8 W8 Q4 w) J: ]
  25. ( o/ E+ u6 F9 U
  26.     # php中的文件锁 * b/ X/ H! {+ W) A
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    , _4 B8 N9 F6 N* _8 E$ ^. `
  28.     flock($fp, LOCK_EX);// 排他锁   W5 F* r, G/ P' N5 ^" J( v
  29. * Z9 e  ~( V) D0 R0 L# v2 C; X5 @
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    8 G0 ^. u; m' {  a  t
  31.     while($row = mysqli_fetch_assoc($retval))
    3 F. ^% u, {( o3 Z
  32.     {, V0 Z- {7 p4 Q% F/ N
  33.         $id =  $row['id'];! \6 L$ i* S: \4 k
  34.     }
    * }% F* I! _* w# |
  35.     : p" l) U" L, m, R: x5 q  D
  36.     if($id > 0)
    / ], C. S& N1 x$ M3 o" i! J
  37.     {
    / l  E8 I+ Y# z6 l" U
  38.         --$id;
    1 ~' R1 O0 Q/ N+ @2 n& N
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    , M" G; U& H$ Y$ ?
  40.     } % @5 ?6 _, l6 `$ P) u/ G$ I4 c
  41.     # php的文件锁,释放锁 - }  _1 A4 k3 ]' _
  42.     flock($fp, LOCK_UN);
    7 n4 w  r7 _( f6 v2 y& G6 W
  43.     fclose($fp);
    1 |8 f8 Y; d/ X2 a  p  O
  44. 9 e. g# x9 w6 g+ n3 I1 j
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ' q2 P# t, |" j: Z/ E
  46.     // while($row = mysqli_fetch_assoc($res))9 R- {# K) N. \' p6 b
  47.     // {
      S, O7 U% o1 U% ]0 \' I) U
  48.     //     $id = $row['id'];
    6 y( ]! y3 L" _6 S: ?
  49.     // }
    6 D0 P* J% Z) z( p; ?: S' ?4 E
  50.     // echo $id;
复制代码
9 J# {* q8 Z4 `2 Y8 C4 w8 ^
/ J  p+ l: n5 X/ P
抢券活动实例:
  1. public function envelopeSnatching(){1 x5 E7 H" E9 w1 d% j" R
  2.         $lingqu = $_POST['type'];5 W: D7 a* \& p. `2 i# n
  3.         $uid=session('u_id');//用户id
    ; q, f! Y5 V8 C$ z) }9 l
  4.         if(!$uid){: n! t6 {. O/ M; O7 u/ r
  5.             $data['msg']='您没登录,请先登录!';
    2 j& ~6 J! g7 t$ ~
  6.         }else if(date('Y-m-d') != '2017-12-12'){; m2 f: S) C0 C4 ?
  7.             $data['msg']='不在活动时间内!';: i* A' ~# F* v0 a; g2 @4 o
  8.         }else{
    $ E$ i/ g# j0 c4 z5 v
  9.             $hours=date('H');//当前小时数) `' i* c, K9 g) f- ]/ H* e8 o9 ~
  10.             if($hours > '09' || $hours > '17'){
    ( Y$ S4 g  c9 c3 b2 a
  11. ' O3 B% \5 m9 B# M  B+ S& Y- p
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    ) C! R2 d) Q1 O3 d
  13.                     if($lingqu == 1){2 x2 j& q0 w! u2 M2 ?. E. H4 h
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    ) n/ [' X# ]" p/ P% s) T
  15.                         if($hours > '09'){5 f: \$ G+ ]- o4 W3 Z4 O2 x/ ^! N
  16.                             $num=mt_rand(25,28);//优惠券金额
    . s% ?' m4 T9 Z. r4 D! [7 W; U9 w) ~
  17.                             $id=1;
    ( R, H: z3 L( g$ J" o6 \, w
  18.                         }  g) F) g: `! X- O& r8 _/ {2 C
  19.                     }else if($lingqu == 2){) [% W! p( r6 T3 E( P) Z0 `
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    * a; F$ l. c: h0 {. o8 x5 _6 Q8 q
  21.                         if($hours > '17'){) n9 d% L. H! q+ b$ I) t2 v, {
  22.                             $num=mt_rand(50,55);//优惠券金额, u% a; D0 A7 }: ]
  23.                             $id=2;" a  Q: c4 y. s& Q
  24.                         }/ }. U* A, J/ J5 X& K( M
  25.                     }
    " p. X7 p' ^# l1 F
  26.                     if(!$id){: Z7 J: t) u: U$ {- K
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    1 S" Q) x. W# s% ^1 u$ U: A
  28.                     }else{- Y% r" O  o' L, H- Y& _9 ?
  29.                         if($is_lingqu){: n- F7 R; m1 f
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';# [" L% M" H, @2 J: T8 v
  31.                         }else{2 Z7 G  G' ?+ l; p
  32.                             //锁表* B, A& J5 ~: n- Q! t6 A. l5 e
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    9 d8 e- Z+ k' o$ W0 p
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    - L. Q# n- E! D, z* @% ?
  35.                             if($active > 0){, m: j8 N. W5 L3 S4 `' p
  36.                                 //开启事务3 k+ g. @9 M) z- T* h. [
  37.                                 M()->execute('start transaction');: P) D2 F8 U, d# ?
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));; d) ^4 J) t2 K* ?7 t2 e
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    7 |+ d8 d5 l& u" \5 V
  40.                                 $members_preferential    =    M('members_preferential');; E+ V4 ^6 ]! y9 H# _
  41.                                 //对应投资金额,
    ' R+ b; h' c) _3 `* u# h0 n
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));9 F% E( ]! i) Q
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    ! r3 a3 G' G' ~
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    7 n: }; E1 L" q8 w* k5 w$ S2 n# Y
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券9 M9 L0 F5 |- ]8 h
  46.                                 if($save && $add && $add2){
    2 m8 Q% P" B6 Z" m
  47.                                     //事务提交# T& X; g4 c; B6 |
  48.                                     M()->execute('commit');
    / W7 c) Z: v2 }' Z% V
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    , x" a7 g) ^9 V$ V" }
  50.                                 }else{# S0 A  y0 ~: _4 s
  51.                                     //回滚
    0 b1 P2 H. z  @+ E1 ^4 p
  52.                                     M()->execute('rollback');2 l7 g' E: g& _. p: Q) X; |4 Q! E
  53.                                     $data['msg']='未知错误!';
    # L5 @, H( h; A& w
  54.                                 }
    ! r( q1 L9 r6 P8 p/ Y4 k3 T
  55.                             }else{& |5 Z/ k: \' c; _
  56.                                 $data['msg']='红包已领完,你来晚了!';2 Y; u2 G9 c- g  N  V
  57.                             }
    0 E# G" L" z% _
  58.                             M()->execute('UNLOCK TABLES');- h- T+ }2 |1 y9 ?0 [! a$ k' E
  59.                         }3 h4 h6 l4 w6 y  i3 O
  60.                     }! b, ?3 e! L% H+ r9 E
  61.                 }else{
      o' H) `0 [6 T6 E
  62.                     $data['msg']='非法操作!';2 {5 F# T: \7 y
  63.                 }' F# R* n) n4 b5 w7 u8 p6 j
  64.             }else{1 J& {& f' m0 T* H4 x7 W
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';( n4 ?( L0 [+ \2 e7 z
  66.             }; t. q. L0 A* b0 I! Q7 }
  67.         }/ {# ?7 J8 X1 W, f
  68.         exit(json_encode($data));3 @1 L4 u2 G' j9 s4 _% s' r: N  |1 d+ ]
  69.     }
复制代码

  O7 B. ]$ ?4 A$ }! g
8 c0 O7 {. S, a  F4 k6 l
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 21:40 , Processed in 0.140325 second(s), 19 queries .

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