cncml手绘网

标题: MySQL(表锁)、PHP(文件锁)锁机制及应用场景 [打印本页]

作者: admin    时间: 2022-3-17 15:53
标题: MySQL(表锁)、PHP(文件锁)锁机制及应用场景
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量
  1. C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php   // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
, \, V! D2 {' s; V% `
Mysql中的锁语法:
- V7 `/ f3 o' }! w, ULOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
# q4 V: e8 p" cUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表2 Q: `1 P0 T2 {! H
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
2 i8 S) }: F( Z2 R! k% q6 D, U2 O注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
6 ~5 d; d+ }7 i文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。$ k% _7 `% K0 T' A
测试时,有个文件就行,叫什么名无所谓
总结:
9 X8 f" a  Z- Z. B" i2 @项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:0 z8 \( z9 h4 {3 W- M( u. m* _3 Q
1. 高并发下单时,减库存量时要加锁
5 W1 L% L/ E2 r! g: q2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    ) ]5 `' @' Q& a$ `
  2.     模拟秒杀活动-- 商品100件( g3 P* H! c" h8 h, X9 A; r
  3.     CREATE TABLE ta
    % ]& Q1 |. p: u: y8 t- Y6 I
  4.     (
    9 @. ~+ t0 R- N+ O  ~, N( Y
  5.         id int comment '模拟100件活动商品的数量'& m! J. x: _; ~9 K- W
  6.     );
    " q/ F6 L! l8 i+ x7 {
  7.     INSERT INTO ta VALUES(100);# U# |8 U0 V5 q6 h: r2 o
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件9 z5 c5 `; g7 J+ h8 j5 @& s
  9.      */ 8 f4 I7 d7 C, K/ F2 R; z
  10.     , D1 E( e# ?0 y9 }$ H1 S" i; N
  11.     // 关闭错误报告
    % D; g) _0 W' E3 A' ^% k7 f+ [
  12.      error_reporting(0); 3 X1 ^" C: A- b$ b* ?: N
  13. ( K$ Q5 D" C/ C- S
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址$ W. Q, z0 o9 c- K! W# @/ O
  15.     $dbuser = 'root';            // mysql用户名
    ; b5 A/ V: J2 S
  16.     $dbpass = 'root';          // mysql用户名密码
    7 X0 E/ c/ S- a: p* M
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ' z8 q& v0 J1 b0 b
  18.     if(! $conn ), f3 {6 ?) F# M: c( S3 U+ m5 ^
  19.     {( c+ U7 X) v8 |8 }* M8 x$ i9 C' c+ u& i
  20.         die('连接失败: ' . mysqli_error($conn));1 d* g4 e; Q) t  q( Z6 m
  21.     }
    " S6 J9 R! f8 B% k2 V
  22.     // 设置编码,防止中文乱码
    ! a( D2 c* P3 E5 P, y3 M* d" K
  23.     mysqli_query($conn , "set names utf8");% n. Y7 E3 r/ C  {
  24.     mysqli_select_db( $conn, 'temp' );
    " Y+ n5 M% M' h/ \6 p9 ]
  25. , h5 N  e* o7 U* s3 t: k  ^% o$ ]
  26.     # mysql 锁 / j7 Z- T2 S4 a9 K7 g5 k
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 9 S. L$ b6 f" V0 I" b
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); , f  l- M% L7 o. P. J+ Z0 K
  29.     $id = mysqli_result($rs, 0, 0);
    9 t5 s1 L, M$ e: ?/ J3 ]
  30.     if($id > 0) 0 q5 V7 G. ]) L
  31.     {
    6 d" w. B# x, O% x1 M
  32.         --$id;
    $ Q0 g4 E$ q! T( n
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); , ?1 R; j' p( a* {' Y: l: o9 W
  34.     } : A) L  x0 p) Y8 H& j" d. ^! }) x

  35. 7 ?) L, p7 V6 }0 h; [
  36.     # mysql 解锁 / z3 K) e& r8 K! Q$ m, S/ m: }
  37.     mysqli_query($conn , 'UNLOCK TABLES');( J* m- S4 l2 p6 y; X
  38.     //查询解锁后的id值& h1 S+ D4 y; L/ S
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    2 @, Q8 I% @/ s, u& _
  40.     // while($row = mysqli_fetch_assoc($res))
    1 E% d' n  g9 i* \
  41.     // {) X  N; r& ~' n( k. r7 B
  42.     //     $id = $row['id'];
    9 s( M  g, z3 q, u
  43.     // }8 f- B/ ^. O2 K7 |& X2 B
  44.     // echo $id;
复制代码
* H- S. c5 ^5 _
5 @( D7 Y) O  R/ V* G2 D
* V/ P- C' B% }7 L( Z& c8 n* @' L3 g
PHP文件锁示例:
  1. /*! S9 X( F& i# N3 @( N
  2.     模拟秒杀活动-- 商品100件
    5 k! O/ J% _  ?0 J6 v
  3.     CREATE TABLE ta
    $ ^+ D% o" q% K( O) y, c& u
  4.     (
    ; A8 b( }/ d/ o5 A; z
  5.         id int comment '模拟100件活动商品的数量'4 t# E( ?" m  y% U
  6.     );/ A/ t, A( c2 q' x" @/ v
  7.     INSERT INTO ta VALUES(100);- j8 @$ b- M4 A8 i7 K1 u
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    9 \. k; h9 s# D+ X! K
  9.      */ # K: n+ L9 f3 D# S
  10.    
    / x0 G% K% z4 y+ c; f, R
  11.     // 关闭错误报告
    1 N% c5 ?+ ?2 t8 K) V' t
  12.      error_reporting(0); * O; w# K( N) {$ G: E

  13. % R% p' u4 f9 |5 {+ W4 o
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ) E, i9 d: I* @6 y* {
  15.     $dbuser = 'root';            // mysql用户名, v1 V/ r% x) E# k
  16.     $dbpass = 'root';          // mysql用户名密码
    ; p! E8 ^3 {: M% N& m* T  h
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ) ~8 z6 i% w' g, h+ f' ^" b' X& d
  18.     if(! $conn ); e4 V/ {7 n7 R+ P3 M
  19.     {
    ; p4 V3 R) `: K( e, q
  20.         die('连接失败: ' . mysqli_error($conn));% p+ c* v0 q. B, A4 X2 w! z
  21.     }
    ! Z* F" n: r" f# b8 l0 i
  22.     // 设置编码,防止中文乱码1 C5 g" @0 s; C- @
  23.     mysqli_query($conn , "set names utf8");
    4 o" @4 a5 k2 P9 E/ }' e
  24.     mysqli_select_db( $conn, 'temp' );
    , |5 T3 L1 `& }5 Z6 F7 y7 Q' R

  25. ) Y: a7 ~. {& ?$ P& E: _, X$ O. w5 O
  26.     # php中的文件锁 2 J. r* h+ m% M1 G. @
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 . W+ A  }1 [" R, i
  28.     flock($fp, LOCK_EX);// 排他锁
    - T8 Y# g+ [/ I

  29. . A: Z9 s6 ^( Z9 U9 O# e
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    2 ]& N+ N7 u4 C7 G; w
  31.     while($row = mysqli_fetch_assoc($retval))
    + g4 ?0 _: Q3 I- Z0 f; r- N/ z
  32.     {$ K' a) l+ M1 P+ J
  33.         $id =  $row['id'];1 E9 G! R; p4 T/ m9 Z
  34.     }1 c$ x$ V% Z. V" P' [% R; s
  35.    
    7 S1 k) F; z: j5 w6 i
  36.     if($id > 0)
    # k6 K/ z0 @# J' L- ?
  37.     { . O" @8 c$ ~! x+ k
  38.         --$id; & W7 H+ G9 s! [
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    # J7 p& O0 x) e9 [* f: N
  40.     } 5 w. e6 h/ a/ D8 a. o& K, \
  41.     # php的文件锁,释放锁 ( J, k8 _. |# Z0 F
  42.     flock($fp, LOCK_UN);
    - T4 V$ P; \& O, H4 W
  43.     fclose($fp);4 }/ c" w* A8 I+ L9 C
  44. ( f$ B, P2 Z! ^  Q9 F* F8 H
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');2 }+ I, K* M7 l/ P( Y
  46.     // while($row = mysqli_fetch_assoc($res))
      Z! L. z- I" D( ]- g3 t; h, @
  47.     // {$ L! r1 v: B( c; d! }
  48.     //     $id = $row['id'];
    & C" O  I0 }9 g
  49.     // }
    : F4 Y9 X; y8 _% x, ~
  50.     // echo $id;
复制代码
  I+ c: R  J" m3 y' T, D2 m7 @

: D6 o( R/ n6 m5 \- w
抢券活动实例:
  1. public function envelopeSnatching(){
    6 |8 ^9 }% _: U: S7 d  Y4 d
  2.         $lingqu = $_POST['type'];( p" r, a& R7 u8 H! k
  3.         $uid=session('u_id');//用户id9 Z' b& O6 V6 H
  4.         if(!$uid){
    3 a+ C  ?  R* E3 ?* p5 z( ~" N
  5.             $data['msg']='您没登录,请先登录!';
    7 ~& [1 `; J+ J
  6.         }else if(date('Y-m-d') != '2017-12-12'){/ u1 l- F$ e8 t0 M# n0 {2 I
  7.             $data['msg']='不在活动时间内!';6 S; f  C) G& A5 V
  8.         }else{: R. v/ X5 M) C# {6 A7 m
  9.             $hours=date('H');//当前小时数
    ! ]; T' j5 }1 G  v
  10.             if($hours > '09' || $hours > '17'){! u, s$ v, n- @+ L( H/ e9 ]

  11. ) S1 \& E4 R0 }+ d$ h( h- W
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的: G# }  R; a/ d6 m
  13.                     if($lingqu == 1){4 ^8 w- k' }3 ^4 ?
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过6 }3 l1 x' A9 b9 z( F; n
  15.                         if($hours > '09'){0 ]) i; t5 k3 _2 D9 \( u
  16.                             $num=mt_rand(25,28);//优惠券金额' Q; G! K5 Q. J, C
  17.                             $id=1;  |9 _/ i+ l8 i2 d  B: t
  18.                         }$ G3 P$ k  Q; G  N+ T( q' O' S# H! g2 A
  19.                     }else if($lingqu == 2){
    7 J" C: Z3 B2 O, ]
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    ) y0 i8 q  J6 D
  21.                         if($hours > '17'){
    : V. Z$ n/ t7 K+ K
  22.                             $num=mt_rand(50,55);//优惠券金额1 C+ _. g  V- X, G, N, D0 c
  23.                             $id=2;" Z% M" l1 K( [! i1 \7 A8 I1 h
  24.                         }
    0 U2 [8 z' @  m. r$ M3 X' B
  25.                     }) e3 B$ w& q. ?( `. ]! X$ N' L8 |  M1 ]
  26.                     if(!$id){
    5 m2 {  a0 D& o6 R% ]2 @( s% J
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    0 a" Q% s6 l5 q5 W+ o- g
  28.                     }else{2 S. t7 o0 R& Y8 |9 S  U/ V
  29.                         if($is_lingqu){
    0 r4 E0 M8 M/ o) M5 n3 L7 ~" i
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';: X  Z. ?! F( d! F
  31.                         }else{
    % B8 U% I; \# W$ m0 T* f( N
  32.                             //锁表
    + N1 n; J; P0 @% a  T
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');. a! M: ?7 d/ _/ l4 ~& @
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    ! c. J3 m: g# o3 P% Y1 z* H) _
  35.                             if($active > 0){; ]% [* G% H6 c; p- d- ?& {) y  D
  36.                                 //开启事务
    * i4 S0 T9 T; P% W
  37.                                 M()->execute('start transaction');
    3 Y# M  @2 B. j7 |
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));5 k% O! a3 C2 @+ t! ]
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    , c+ Q0 o# z( q1 k
  40.                                 $members_preferential    =    M('members_preferential');6 h* O( K- r- ^7 T
  41.                                 //对应投资金额,
    - H3 O  N, p9 A$ l- F
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));$ ?6 J$ U5 H+ D9 z6 f
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');, R9 _$ p+ P+ {
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    " P. W4 g, |& l
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券4 a; Y5 a- p0 H1 z
  46.                                 if($save && $add && $add2){
    7 t  n! B/ F& P+ o' i1 `3 S6 A. u
  47.                                     //事务提交% h3 v0 C+ W/ T
  48.                                     M()->execute('commit');* x( f3 v' E* @" W3 d
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';9 q% J6 ^$ u0 v  b
  50.                                 }else{% G: k5 c$ e9 e2 ?9 K! Q
  51.                                     //回滚; E! O, q7 ]! m# W5 Z$ D
  52.                                     M()->execute('rollback');
    9 J4 }  p  I1 I8 W
  53.                                     $data['msg']='未知错误!';. B# N' N  J9 J
  54.                                 }& _9 u8 Y  i; ]9 ~9 G  ]
  55.                             }else{
      K( \' a+ H9 r0 c. f
  56.                                 $data['msg']='红包已领完,你来晚了!';' R* m; |. e, o6 r& R* i8 W) o
  57.                             }8 W  q8 e$ \/ j" J" C
  58.                             M()->execute('UNLOCK TABLES');9 H7 M7 K" }2 f; f6 h+ a) ]
  59.                         }. ?) b: X8 [8 t7 y# K$ j2 t
  60.                     }
    , D! T* y$ F6 y- u
  61.                 }else{
    + E, ^& o1 `' _
  62.                     $data['msg']='非法操作!';
    & }/ a5 _! _* ?5 C+ p$ A
  63.                 }
    8 P% [5 C7 m& c; E; r/ q  v
  64.             }else{! [  B: a* `. o9 u1 Y) m
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';9 B. p& b7 b! x9 N, z+ j8 [5 X
  66.             }
    + n  x9 i4 H& c2 n/ d, r
  67.         }' v$ ?' y; s7 T- ~
  68.         exit(json_encode($data));
    + j  N6 [4 t/ x& X7 r
  69.     }
复制代码
. D: L& l. B8 q. U) o! M4 h

& ]" C* z% m( }; w




欢迎光临 cncml手绘网 (http://cncml.com/) Powered by Discuz! X3.2