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://请求的脚本
复制代码
1 u0 s4 B9 V4 M# H
Mysql中的锁语法:) ]' q& a- d5 W2 Z$ N
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】8 n$ B; u1 V6 }0 C
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
2 \) g6 W, g  p$ U8 g! ~* N* _- x2 VWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
2 m) ]1 B" x9 d' j+ B# b. f注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :+ j2 }* E( ?' b$ m
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。4 a9 t# B9 a5 _# Y! V( y6 Z8 x3 M
测试时,有个文件就行,叫什么名无所谓
总结:
4 |: l$ _# V1 M2 W7 p% p项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:1 o( w; C% n" {# e* |5 U3 K
1. 高并发下单时,减库存量时要加锁9 T* I* t  r; V& t# _) f0 U
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    " _1 ]( L) U. U. c( f5 S4 L
  2.     模拟秒杀活动-- 商品100件4 W8 t" ^- W# V2 ~7 X
  3.     CREATE TABLE ta. L+ j" W% w% ?* o4 I
  4.     (
    4 X! a. m* }; X7 r
  5.         id int comment '模拟100件活动商品的数量'
    ( T- ]' \: v3 ~0 l
  6.     );2 L3 ?8 X+ k$ M  V
  7.     INSERT INTO ta VALUES(100);7 z/ L% X# w5 ]3 }/ e
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件9 Y) h# R2 O2 E0 Y7 B- L
  9.      */
    8 M# Z/ D* _" f" N! j
  10.     " p" M6 R1 F  h) s, F
  11.     // 关闭错误报告
    : N3 P2 n9 x/ B" u
  12.      error_reporting(0); 7 m2 i0 j; F* U

  13. % w- C5 j; P! Y2 l( N) w
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* i/ l2 D4 I2 g9 T& }, G
  15.     $dbuser = 'root';            // mysql用户名( L# A& d& s+ [( p
  16.     $dbpass = 'root';          // mysql用户名密码, O2 H" \+ {! d  u
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ) `& e9 \% L# K  }. F4 ?! X
  18.     if(! $conn )
    ! C6 v" l# {  I8 i
  19.     {: T! D' S9 W$ k
  20.         die('连接失败: ' . mysqli_error($conn));
    * H% \0 U) I+ S) o* n
  21.     }4 @5 `4 k7 ^- F8 _$ f6 V1 j4 F, r- U
  22.     // 设置编码,防止中文乱码. C( l4 M/ ], Z* C) I
  23.     mysqli_query($conn , "set names utf8");
    3 T# [& M' q; Q8 \% z0 @
  24.     mysqli_select_db( $conn, 'temp' ); # j9 ]7 x" i8 C0 }+ y

  25. 8 ~8 n# s! |0 S7 G. Q& e# _* R( J7 W
  26.     # mysql 锁
    ' u9 U2 D1 X; M, y" j6 @
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    5 ~7 F' I. l; o# f9 d4 Y5 t
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    % {* L$ @* x! J! M9 f/ u
  29.     $id = mysqli_result($rs, 0, 0);
    ( w3 Z+ p4 j% }" @$ k3 A
  30.     if($id > 0) - n9 W8 D2 f9 m" x* ~
  31.     {
    8 ~" a8 n7 {5 M% j; K5 i# l- A; o
  32.         --$id;
    0 G* p& k8 r$ y0 O4 U- L
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); * ~% @9 X& G" w$ F
  34.     } : ~& y$ M0 s& c/ ?( G$ A
  35. + n0 O$ n3 T" j; u* ^
  36.     # mysql 解锁
    0 m# d9 ^9 z5 X
  37.     mysqli_query($conn , 'UNLOCK TABLES');  y+ Y  F' T' d- Y
  38.     //查询解锁后的id值
    ; o/ `# }- ]. D* W+ k) V: g
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');! W/ t8 n0 c: p: S8 p
  40.     // while($row = mysqli_fetch_assoc($res))* E( f' k( N  D0 ?. p# p- Z9 e  W
  41.     // {
    * z, n# I" @3 u
  42.     //     $id = $row['id'];
    0 q# _& }1 J* y6 H
  43.     // }
    % p; w9 q$ G  L( m- d
  44.     // echo $id;
复制代码
, l, W) X* @. p) ^8 E
0 z' E7 O6 u( _% E
. M" W  b% g! T) Z
PHP文件锁示例:
  1. /*9 i: r7 q  C/ _; a3 q
  2.     模拟秒杀活动-- 商品100件+ o& @7 R2 {" g
  3.     CREATE TABLE ta
    6 d8 i4 g+ q& F6 G, \2 x- K/ x
  4.     (
    ( d5 y$ n  [$ x  p2 a
  5.         id int comment '模拟100件活动商品的数量'3 d; {/ y7 H1 T0 t1 F9 j7 A1 B
  6.     );
    ' C% r0 r; W9 A. [, Y
  7.     INSERT INTO ta VALUES(100);" U$ T* E, R, K: S4 E, V$ u1 w
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    8 d+ ]+ D0 d3 l- z8 a
  9.      */
    / w6 ^* i3 q# L
  10.     , Q/ `6 X  {8 ^+ Y9 E
  11.     // 关闭错误报告2 Z& Q- O* Y" F$ o: |9 M
  12.      error_reporting(0);
    5 u5 @' v3 _+ b0 l6 Z/ V
  13. ( {1 W" \1 M& m7 @8 }; d0 E- p$ C
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址0 M9 Y# F" f& J" N5 D1 @
  15.     $dbuser = 'root';            // mysql用户名, ?' U! M2 ^2 v( y
  16.     $dbpass = 'root';          // mysql用户名密码/ `5 ?! C' O& I0 R6 m" r2 {$ y
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    0 D0 ?# X$ E. `' H! {( d
  18.     if(! $conn )6 w2 L/ k% ?; h& U# W! D
  19.     {
    8 E; N+ S4 G, H$ X
  20.         die('连接失败: ' . mysqli_error($conn));: @4 m  H) H* I" J! ]- q2 B' \5 P
  21.     }/ K0 t7 }  Q- d- }0 {* P- M  ]
  22.     // 设置编码,防止中文乱码$ m3 @4 _" t5 l! u
  23.     mysqli_query($conn , "set names utf8");
    5 t, R. V* u0 a6 \" H% X3 f1 C, G6 F
  24.     mysqli_select_db( $conn, 'temp' ); * E3 }+ o% K' X6 `. Y7 j# a
  25. 7 O, |4 y$ j* z
  26.     # php中的文件锁
    : H- _6 a( \4 `
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 : i1 p9 S1 R; w9 ~5 `
  28.     flock($fp, LOCK_EX);// 排他锁 + O6 _) t6 ?0 `( r1 _, s) e

  29. , Z& }" L2 F0 D2 z
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    . F$ d, }. u3 U! J' j9 D
  31.     while($row = mysqli_fetch_assoc($retval))
    # w2 f0 ^7 A4 n$ m5 |; f
  32.     {
    0 t& o* B7 T6 Y
  33.         $id =  $row['id'];" a  P# V# a( W
  34.     }8 ~4 H* d7 d0 _  W. L, ~9 R
  35.     $ C  S& m* G$ k* c& Y$ S
  36.     if($id > 0) 6 M/ Y0 C; _! l/ U6 x
  37.     { 7 _$ H9 e6 r+ L% R, `! l7 m
  38.         --$id; 3 w( T) b, o1 B) W
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 2 w. k7 F9 l5 T4 Z5 S$ ?3 \
  40.     } # l9 r  t/ ?! |* q% c; J/ q
  41.     # php的文件锁,释放锁 4 K% k, K& u& o* m# j% `
  42.     flock($fp, LOCK_UN); % V( D0 d6 V1 }! a& |7 Y& o
  43.     fclose($fp);3 M1 ^. l: T/ Y. g8 A
  44. # z7 ]7 U/ U- Q! Q8 y* f+ Q
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    : u: q% k5 z8 L- N
  46.     // while($row = mysqli_fetch_assoc($res))
    " q: N8 Y+ D& M+ u& o
  47.     // {
    & }+ Q. V& g. {4 l$ u
  48.     //     $id = $row['id'];
    ( @5 _+ p( B1 O* Z  a
  49.     // }7 t1 h6 f0 K, G
  50.     // echo $id;
复制代码
' T3 B  V. q% Q  c3 o  t
/ C; R; j7 E3 e' L. I8 d& S
抢券活动实例:
  1. public function envelopeSnatching(){/ B$ k! J  H* `6 p
  2.         $lingqu = $_POST['type'];( W; [1 m& j4 J% r* i
  3.         $uid=session('u_id');//用户id% W4 o  U+ a& R) w9 p0 d8 V
  4.         if(!$uid){- t" |0 b6 A' ?9 M% A
  5.             $data['msg']='您没登录,请先登录!';2 `: }6 o: D9 A: d
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    9 S5 V; h; B# N/ L( o6 ?1 K' r% f$ ?2 R
  7.             $data['msg']='不在活动时间内!';
    * L8 J9 O% U6 P) w7 t! w% Z
  8.         }else{
    # Y1 v8 H( L8 N% W( a' t) P
  9.             $hours=date('H');//当前小时数
    . u2 S4 i3 N% ^3 y6 @
  10.             if($hours > '09' || $hours > '17'){7 V7 ]; u% m+ V
  11. 4 J$ O9 h* T; a0 N8 N
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    - Z% F0 ]/ @( B
  13.                     if($lingqu == 1){
    : t1 S1 |/ e" I9 `0 V
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    9 u2 @" B% B1 I% J  d
  15.                         if($hours > '09'){
    0 x9 M2 `& \# r4 |
  16.                             $num=mt_rand(25,28);//优惠券金额
    % J% y0 u' U0 l" o
  17.                             $id=1;
    - P' A2 E4 o+ z" ~
  18.                         }" M8 C2 \" I; T
  19.                     }else if($lingqu == 2){& B1 h' i+ {2 A
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();9 Y! l! b, n1 z" I+ h- s4 F: q% L% S
  21.                         if($hours > '17'){
    4 L% L4 o# @  B" A  H
  22.                             $num=mt_rand(50,55);//优惠券金额
    : r, I) F' M  f& M4 _2 a
  23.                             $id=2;9 _0 v0 [! x3 P' D+ R
  24.                         }
    : x) C+ U2 L# p+ S/ m
  25.                     }2 }: `* }. M8 t# `% x
  26.                     if(!$id){7 }4 r: F* n' q# F, F
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    / {+ T/ W. [+ M* |. G9 U  ]! D' ^
  28.                     }else{
    ) Q( h( p2 S  z* s; ^: m' v( ?
  29.                         if($is_lingqu){
    4 d/ H: A5 W( e& k7 _+ {0 l5 Q
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';* G1 u# n" A3 L& `  @; i& W
  31.                         }else{
    ) e) l' {% n# W: ]8 y
  32.                             //锁表
    9 p% c( k, W% J0 A2 _
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');9 S+ F3 @0 U3 \3 L, W. k1 |
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();8 H# F8 E7 ?- K; u: k% K
  35.                             if($active > 0){( {: s) ?- P/ ^
  36.                                 //开启事务3 s& A& [: t% R
  37.                                 M()->execute('start transaction');
    + T# T, u: c$ n
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));7 \  `; @' H% }+ F+ x6 d% T
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));, d0 Z! \% r! A% ~& D+ p
  40.                                 $members_preferential    =    M('members_preferential');0 O* X2 ]" \8 X( s: t
  41.                                 //对应投资金额,2 x1 J9 O& e6 H
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    / r# N: L5 E9 f/ Y" ]( u
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
      U2 {1 j- |  W9 {# r9 }
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    0 ?) \; A. F! {  \3 n  ?0 d
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券+ X- ~9 g- ~' e0 h
  46.                                 if($save && $add && $add2){
    + E4 _0 v) p4 v
  47.                                     //事务提交
    # n6 j( T8 W0 f
  48.                                     M()->execute('commit');: e! I" A7 L; D' L
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';4 n$ _" _' `. J- F" t
  50.                                 }else{; \8 C9 Y6 I- N1 Z9 V3 c
  51.                                     //回滚! ~2 i4 S5 `' v( q! [: }
  52.                                     M()->execute('rollback');
    , Z* A5 Q- T! A4 K3 G: Y" I
  53.                                     $data['msg']='未知错误!';9 j, r" Q5 u0 S  A) w& ]; w
  54.                                 }5 a7 U) H. v) r
  55.                             }else{
    - o- d. u- s5 z
  56.                                 $data['msg']='红包已领完,你来晚了!';
    ( r+ D' s1 k6 W- J: x
  57.                             }/ {! L# }" Q5 G
  58.                             M()->execute('UNLOCK TABLES');) g- D. v5 K+ |5 T& e/ P$ k
  59.                         }
    ! G! ]5 x% r6 V6 |1 o
  60.                     }3 r6 q/ t5 a+ p; K5 Y2 @
  61.                 }else{- i9 g2 Q, @7 {
  62.                     $data['msg']='非法操作!';7 _7 ~9 v! l0 s7 p' [/ _; p- U
  63.                 }
    : f* F6 j! _5 l
  64.             }else{
    3 A4 J4 k- [, P% q& ?& F
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';/ L% G7 u. D9 o
  66.             }
    1 h9 O% r' @$ |
  67.         }5 L# J5 s. G# U( a$ B) g
  68.         exit(json_encode($data));
    ; Q% j# a8 b, J$ Z. [
  69.     }
复制代码

" S1 d6 M& v& e# ^  X& U; c
' P' I5 x. z; \: w0 g




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