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

+ J' @7 m; t) C: F5 I" C3 t7 ~8 R! Y
Mysql中的锁语法:/ d: P' {$ T: \) v
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
. [& T" ?' y+ \2 s9 @2 {, [8 rUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表5 c+ X* f; U) ^1 L8 |5 p/ N4 C' N7 U
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞6 b  p8 i$ C+ ]% U
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
4 Z/ S8 h; N7 U8 Y! p+ r7 x文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。5 Y" H9 E1 Z* w- V5 S- {# Y
测试时,有个文件就行,叫什么名无所谓
总结:
; J% b' G) D3 W; r, w& o项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
: \1 o9 b( ~$ M- j7 N4 k# T1. 高并发下单时,减库存量时要加锁4 Z9 T" ^, v6 f8 S* C( k! i
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    , O& b; G" j8 ~
  2.     模拟秒杀活动-- 商品100件4 E9 s. Q9 e  J- R, U4 _
  3.     CREATE TABLE ta! d& M, U# \/ ?0 \
  4.     (  Q$ ~: S8 i- M# q; C
  5.         id int comment '模拟100件活动商品的数量'
    1 z7 M7 E0 l: P3 U) Q6 k
  6.     );
    " ]1 u* v3 K1 D, r& C9 X3 s, D
  7.     INSERT INTO ta VALUES(100);; n; j; M( {; n% X' z, d
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件8 R- v' q  W5 Z* o) X( G
  9.      */
    8 s) d) d/ [1 t$ g! g
  10.    
    2 Z3 r+ k+ ]: i$ }
  11.     // 关闭错误报告; S' f! I' T) d" {' B8 L
  12.      error_reporting(0); & Q4 e* F5 I4 R# A+ l- F2 C. ?

  13. * e, c( R& f' g2 w6 \% L
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址  p# q  W$ p) K) a
  15.     $dbuser = 'root';            // mysql用户名. i' S) Z0 [( v& L+ F- G" O
  16.     $dbpass = 'root';          // mysql用户名密码
    , W6 G4 B( g( E5 z+ F! U
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);! ?: P$ f( B* u: D
  18.     if(! $conn )# n- L: x; `3 P" _7 l4 n& N
  19.     {1 V4 g7 e  o$ C# v
  20.         die('连接失败: ' . mysqli_error($conn));! c# r' a, }* D; |+ [* P1 `; ^
  21.     }# [- I) e; q% L# S8 x
  22.     // 设置编码,防止中文乱码7 A6 S& B+ `" {4 j) T
  23.     mysqli_query($conn , "set names utf8");- U+ ~; k# e, l' g) i" o
  24.     mysqli_select_db( $conn, 'temp' ); * }2 E2 H$ U' Q. i
  25. / Y2 b4 R" H5 I
  26.     # mysql 锁
    ' F  O; |) Z; U3 U2 }3 v
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 0 I; {3 a' p2 P3 d
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 7 k8 J" [4 x+ |6 h% K$ j. ~
  29.     $id = mysqli_result($rs, 0, 0); 6 a# `, @- L; s4 z
  30.     if($id > 0)
    ) P3 g/ N9 \$ M/ A$ `
  31.     {
    2 Z3 n' b( O# W2 F, r
  32.         --$id;
    ' K" T5 w' i  W3 \
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); % X, j- E9 @- ~+ f
  34.     }
    9 j3 Z, }# }, N3 D3 x
  35. ; z$ `- G0 h+ V: U( W; k! }3 C* Z
  36.     # mysql 解锁 ! W( A4 O  c1 w0 i6 u
  37.     mysqli_query($conn , 'UNLOCK TABLES');/ {5 Z* U+ B6 L4 D5 Q! _8 g1 u/ n
  38.     //查询解锁后的id值
    , |; l/ L, b2 x7 I% P0 E
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    3 ^/ R: v5 F$ N& y+ P2 D2 x8 K
  40.     // while($row = mysqli_fetch_assoc($res)), _6 z$ o- [8 w2 h% f
  41.     // {4 v; i& ?, u, w" S, |, T: R% @7 Y+ u% g
  42.     //     $id = $row['id'];( X# I% F' g; `* `) U/ q: L
  43.     // }9 t- t$ `5 L0 ]3 H' ~1 Z- E
  44.     // echo $id;
复制代码
" ?6 x7 x: ~6 V/ k
) R5 c. L$ M; K( u5 [0 y! v& r
( @$ e1 v2 r0 T' z1 i
PHP文件锁示例:
  1. /*6 L+ T, _$ \6 b
  2.     模拟秒杀活动-- 商品100件
    7 F$ ?& a' e; I+ p6 |7 X- q7 k
  3.     CREATE TABLE ta
    ) b0 |* z+ B: u; u: B% P/ {
  4.     (
    " u/ u7 F/ i- N9 }' B- G
  5.         id int comment '模拟100件活动商品的数量'
    7 |9 [  `' g$ g7 w# [, L
  6.     );
    % D8 l% I3 C+ B$ `
  7.     INSERT INTO ta VALUES(100);
    ) b, y- \" r7 A( q$ f  W# U" l
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    7 x) x0 G. _/ D+ z
  9.      */
    1 u2 m, O$ Y( b4 r" Q
  10.     ! s& i6 P; p6 A) x4 Q
  11.     // 关闭错误报告
    ) ?; A. z! J6 d: X  s, m6 S
  12.      error_reporting(0);
    6 g* ]+ }) F5 C9 s7 G+ }. ^
  13. 7 d8 y8 ^+ V$ m9 J; }2 y% x) M0 z6 q
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ! S8 W- O, P# v5 f1 j9 `- ?2 c/ H
  15.     $dbuser = 'root';            // mysql用户名
    ) M3 W' }9 y( }% M  c4 Y* }! C. O
  16.     $dbpass = 'root';          // mysql用户名密码3 Q* f  l# S* t# m4 A) L" P
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);' o* ~. P4 ^% d4 |! G( p
  18.     if(! $conn ): O+ v' v: P2 U$ S6 _, S' p5 M) O
  19.     {- U+ E2 G( u) m( B: Q5 z( t3 U4 S
  20.         die('连接失败: ' . mysqli_error($conn));8 q3 Y2 W6 C% l! a; O1 U" \
  21.     }' I( @+ _; ~" A, P( f2 O
  22.     // 设置编码,防止中文乱码4 q4 h( t; I1 l4 m  j
  23.     mysqli_query($conn , "set names utf8");
    ( p, q1 f& ~0 Q2 V  u
  24.     mysqli_select_db( $conn, 'temp' );
    ( i9 [) T$ H  D8 E) Z4 }

  25. & @9 E  C. q; l4 V
  26.     # php中的文件锁
    1 h# z) Q% g1 T! {; t2 _% j' r
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    ! t4 T" g1 ^/ K- F0 ?% f- e6 N
  28.     flock($fp, LOCK_EX);// 排他锁
    0 w% t1 R* f2 _% w3 T# O
  29. 1 A2 Z0 H* @; C3 H! B9 N
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    . S% F8 O' A* z' p5 J
  31.     while($row = mysqli_fetch_assoc($retval))- a* J4 Y6 ?2 X
  32.     {6 ?' |0 C7 g# G
  33.         $id =  $row['id'];
    ) ]  G# @$ G+ o8 Y$ t" Z+ i
  34.     }
    ! W9 C8 [. f  V+ Q; _. H- s5 d
  35.     ' B" _9 }& p' s; S/ J6 U
  36.     if($id > 0) , F( {) a; y4 X
  37.     {
    2 `8 }" n. l9 E; n0 N! O% `% J* B
  38.         --$id;
    ( h% @3 S% F- I8 @
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); - A: G4 v. Q+ V4 C* S
  40.     }
    : v8 R6 F6 Q! y, p# P; d
  41.     # php的文件锁,释放锁 ) U/ [5 w% B; G( t: J- S7 M
  42.     flock($fp, LOCK_UN);
    6 O, ~, v" G( R- f7 c1 k0 f7 d
  43.     fclose($fp);3 ~* q" b* }: {! X' C/ j" B' d8 s, l' O

  44. & W4 |4 w& C& G2 K2 G
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');& @& {- @8 _) Z0 p) t
  46.     // while($row = mysqli_fetch_assoc($res))
      o# G9 E9 z% ^4 ]: T9 I- r$ j
  47.     // {' {! q3 p+ b; v& S8 H2 R8 K
  48.     //     $id = $row['id'];
    ( l; f0 B- l: J. \; N/ {, j
  49.     // }
    7 ~$ f' F$ C% |9 r/ g
  50.     // echo $id;
复制代码
3 G1 p$ I( `2 v# F- Q( c
! |  t" A! X  p( k
抢券活动实例:
  1. public function envelopeSnatching(){: e- D& ~' u3 Q/ D* s9 {& c
  2.         $lingqu = $_POST['type'];
    : C# ~- c, Q# g$ z! S& G" L' Y1 b
  3.         $uid=session('u_id');//用户id+ j5 h* ?) _! n8 z+ v) ?1 X
  4.         if(!$uid){6 ]% ?! }( C" _7 i
  5.             $data['msg']='您没登录,请先登录!';
    / {) j( g. d6 \* M
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    , c* I: B  I2 t6 a) Y; M
  7.             $data['msg']='不在活动时间内!';
    & V* @( v) T( K" ]) B4 O
  8.         }else{' T6 F% P, V* L
  9.             $hours=date('H');//当前小时数  r8 b/ @% ]5 J7 L, r0 e
  10.             if($hours > '09' || $hours > '17'){" u: {6 s4 ~. c' O

  11. ; L. W- [- d' V# O5 c
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    9 n. {9 z, g4 Z( k2 }/ b
  13.                     if($lingqu == 1){
    ( f( I. p9 K$ {* U6 t7 L
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过2 |6 b: ~! V3 h# t8 R/ y5 U) c
  15.                         if($hours > '09'){
    : b% c+ }) j3 @4 [4 \2 z; i
  16.                             $num=mt_rand(25,28);//优惠券金额
    + R* u# j; W. j
  17.                             $id=1;" S% j% W: j- b0 Y( V
  18.                         }
    ! ~9 Y3 X7 K; g
  19.                     }else if($lingqu == 2){. M, w1 l; m% e
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();4 M! z$ [8 D) l( Z  Z9 {+ d
  21.                         if($hours > '17'){
    ( F* o' }; p& N; w5 L- ^
  22.                             $num=mt_rand(50,55);//优惠券金额/ d0 P2 H9 r! x! {
  23.                             $id=2;
    ( d  B. l7 Z, m$ i
  24.                         }
    * `6 ^2 `5 v/ X% W( {
  25.                     }
    ! s' J4 S5 H/ ?# _
  26.                     if(!$id){
    " s3 S  X: I  A% D+ o
  27.                         $data['msg']='时间还没到,晚点再来吧。';' j, t: l( y6 ^" I
  28.                     }else{8 r2 ]- @  X1 {) B$ s0 q) v
  29.                         if($is_lingqu){; w; C1 A! `+ D
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';: {3 S' I, @- C+ N! d3 w! g& |/ I
  31.                         }else{
    9 K: Z4 Y  a: J0 ?/ t4 J1 r
  32.                             //锁表
    0 O4 L, ^. ]. }/ e  o4 o$ I
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');& z8 a  [0 Z9 T9 r
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();8 I  Y- o9 Y5 v+ t) @1 K1 R, e% r
  35.                             if($active > 0){9 ]6 P1 e9 v. {3 s
  36.                                 //开启事务# Q* `9 K; h* s0 m5 H2 ?
  37.                                 M()->execute('start transaction');
    # L: d0 k. P8 l, u' G: y: Z
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    # A3 J  B# l3 d% L8 P
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));8 B* G8 m1 F" t# l3 R% ?, }  i+ J
  40.                                 $members_preferential    =    M('members_preferential');
    6 ]3 ]) [6 h; f, M
  41.                                 //对应投资金额,4 |5 b% E) [' ]: R/ [2 @4 E" [
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ' P  a8 T- k" |& f$ J  Y2 |
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    * h& B7 S, R( X1 @2 D
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    " Z5 x# y( r/ _5 m% r, G& P- t
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    / w& J/ I9 D4 S1 z# _4 P
  46.                                 if($save && $add && $add2){; k; j) ^: g% u' n  R1 J
  47.                                     //事务提交
    $ E4 Y- f" s; {
  48.                                     M()->execute('commit');2 G, C# w2 V! R8 i! N
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    1 A3 D, z' p% s3 W
  50.                                 }else{+ e& w3 R' L$ P. V5 [% K$ m1 ~
  51.                                     //回滚
    % b2 b5 O: u* i& @: D
  52.                                     M()->execute('rollback');
    + v/ U6 O, }! T" Z8 X
  53.                                     $data['msg']='未知错误!';, ]! N2 d, t# u
  54.                                 }. a# `; e* {$ e+ L. A
  55.                             }else{
    : N0 a" c% T& B5 ]
  56.                                 $data['msg']='红包已领完,你来晚了!';# t  _. C! n( B4 [4 }( ~; \) n+ Y
  57.                             }3 J- s5 ?. a; p0 C
  58.                             M()->execute('UNLOCK TABLES');
    ) n. T8 `, a4 W& a1 F' O. W# i9 _
  59.                         }8 g  R% ]# B4 }- M) c4 {! G4 K
  60.                     }7 k% J4 A+ L1 ^1 Z8 O: x6 R0 n
  61.                 }else{* S3 R' j4 A3 n$ l! H4 |9 V+ F
  62.                     $data['msg']='非法操作!';
    & ~1 O2 E5 n2 [( f6 e; ?; D
  63.                 }
    9 E, }; K# Q! R$ Z
  64.             }else{
    ! J; U2 B! x: k  C) D, ~
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';4 n/ f. T; y& f+ y
  66.             }
    / e( Y$ p5 U! R% T
  67.         }
    % p  Q  I* B' z
  68.         exit(json_encode($data));
    ! h6 }& N7 B3 @! ]' Y& G9 r
  69.     }
复制代码
  ?/ `' L0 N6 `
; P1 L& B+ G- y. i2 \, i$ U





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