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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 4013|回复: 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://请求的脚本
复制代码
- [& p. l. f( r4 N. _
Mysql中的锁语法:
6 ?6 t) n, s3 w# Y) s7 Z/ X3 uLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】  H1 ?$ D2 n9 Z) [
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
4 a) v# o6 s8 p2 _" q8 gWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞; W5 ?3 Z1 |. O( q, c
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :. c1 o1 i$ Z; Z: r7 E6 j
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。1 J; a( Q9 \! `, s! y& F0 \
测试时,有个文件就行,叫什么名无所谓
总结:
, d* [  F- K, e7 A* m. _. A项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:$ Q1 I4 Z) W% I2 P/ t
1. 高并发下单时,减库存量时要加锁/ Q: g) D" K$ u
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*1 N) s" Y4 x& t: \' {9 K; [
  2.     模拟秒杀活动-- 商品100件
    , ?8 b0 K  E& O2 w$ |# B5 t) p, s
  3.     CREATE TABLE ta
    6 z/ d0 w  ]$ v; A
  4.     (1 J7 D0 m: [0 M! P/ W
  5.         id int comment '模拟100件活动商品的数量'$ D/ V: t" V- o- |+ J
  6.     );5 Z# p; {: e9 Z, S9 Z
  7.     INSERT INTO ta VALUES(100);8 K3 N4 B! B. {6 Z2 w% T
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    * @* Q! }- g8 Y/ r% X/ |$ a
  9.      */ + ^) n& Z9 {* \# D+ i
  10.     - v/ X. h$ h1 Z$ c6 c2 Q6 F4 @/ h
  11.     // 关闭错误报告
    " x; {; e& @* A' d  d- g; O8 {
  12.      error_reporting(0); 0 ~( S: H: i% n$ o- p/ _) n
  13. $ n5 Q7 O6 G. t- v( }# N
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    + P+ A5 k7 [. t. e( v4 m1 i2 \% Z: @- |
  15.     $dbuser = 'root';            // mysql用户名" g3 F! H9 {9 \1 s- [( R' g
  16.     $dbpass = 'root';          // mysql用户名密码
    0 y' }. G6 Z# }
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);$ A  Y! C" j2 f8 f
  18.     if(! $conn )5 M& ]! ^8 p9 {$ [
  19.     {1 w. W: G/ Q' J: t$ t$ h* w3 ?
  20.         die('连接失败: ' . mysqli_error($conn));1 g! w; k+ d2 Z- `. W1 @
  21.     }0 B+ T1 w/ ~$ M$ {+ z
  22.     // 设置编码,防止中文乱码7 T9 D9 j! }: A7 `: E6 h' y
  23.     mysqli_query($conn , "set names utf8");$ W0 W/ P9 ^$ B9 t5 N
  24.     mysqli_select_db( $conn, 'temp' ); % I* w3 [/ |- D/ W, ?

  25. * W1 t; U9 D) O" L9 o
  26.     # mysql 锁 6 ~- X+ \6 ~3 v) G$ i1 R* s
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    6 h3 I. ~/ L+ A; B
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    0 o( ~; y; |# v# k% n' o
  29.     $id = mysqli_result($rs, 0, 0); 9 R0 \. m" I* K0 i7 N- F: M- C
  30.     if($id > 0) 9 Y+ z& B3 E# \) F: P" N5 y
  31.     { 1 f4 R, |) ]# v# `- x
  32.         --$id; $ Y0 n8 v+ [9 G1 _, ]
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    ' ]2 q+ K0 F& A5 ?4 [* b' R- f
  34.     } 6 s9 x1 O+ W( H9 W

  35. 8 U0 z1 G+ P! Y1 I0 P; |
  36.     # mysql 解锁
    # e' g; @! g2 u3 X) x; c
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    - T. [: V$ R1 M( s# Q
  38.     //查询解锁后的id值
    5 s% f; u9 ?/ M' j0 g8 L
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    2 P' x) ?2 v- t- q' S8 y
  40.     // while($row = mysqli_fetch_assoc($res))  d/ y7 G6 ?4 L: o+ {
  41.     // {3 D# a9 |9 I9 _" B# N
  42.     //     $id = $row['id'];* G$ S3 W$ w9 q
  43.     // }
    - Y; P4 w6 f$ w+ |/ I& `3 ^1 i
  44.     // echo $id;
复制代码
$ F& S3 h2 F. z; q. A! g- o

% s9 K2 O5 g/ C& r
3 Z! ^) t0 o) ?+ J
PHP文件锁示例:
  1. /*9 x8 R! W; `" \5 I0 p
  2.     模拟秒杀活动-- 商品100件) G! m4 k( R% g' M0 Q7 t
  3.     CREATE TABLE ta( {9 D. u4 s6 U( E$ g; t
  4.     (
    & I2 ?/ T. C+ ^$ l% u
  5.         id int comment '模拟100件活动商品的数量'
    , _0 s- k" f# V0 S
  6.     );3 t7 g0 W& T# \6 ]/ u$ r
  7.     INSERT INTO ta VALUES(100);
    7 P' `# c0 q" @5 c1 q7 N& E
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件! E; }) g* ~- {, E( A: V5 L  S. ?6 w
  9.      */
    ( ?# C. `- f! z6 Z# }
  10.    
    * P, X6 H0 f$ g
  11.     // 关闭错误报告, m( ^5 X  T0 X! Y: n, e
  12.      error_reporting(0);
    2 N3 D( l- |7 t) T

  13. & g$ g* H0 @% O4 D: C
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址/ a3 M- h8 ]& n. E5 b
  15.     $dbuser = 'root';            // mysql用户名  J; J" \4 D0 B; Y0 d
  16.     $dbpass = 'root';          // mysql用户名密码- X4 ]# O$ Q0 P! `
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);( d0 F( W: B+ E/ K& D5 I' A/ d, L
  18.     if(! $conn )
    9 q$ _  i; s# V# ?/ }+ B; T: f6 |: x
  19.     {
    8 H! S9 m/ [% n. j& K0 q6 N% a
  20.         die('连接失败: ' . mysqli_error($conn));- a3 p5 G  i; R6 V) P; A+ K
  21.     }
    , S+ `6 Y4 \* i) |5 U' h# J% e/ l
  22.     // 设置编码,防止中文乱码
    5 ?8 _3 v( @7 l) V% M+ E
  23.     mysqli_query($conn , "set names utf8");1 u5 j- i/ ~" I1 a3 J0 d3 d
  24.     mysqli_select_db( $conn, 'temp' ); 5 J. r/ J' P$ }* a

  25. ; k. a+ a/ M; j; x2 K6 Y0 @
  26.     # php中的文件锁
    & w2 x2 [% n# @: D" W: I1 x! }8 I: M
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 4 m3 I' |" I1 X( H2 H
  28.     flock($fp, LOCK_EX);// 排他锁 1 E$ H3 n& D" K  c3 C

  29. 0 F! g$ G9 [; `; a. s0 D0 X9 q* T
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 5 K8 h2 |, H( |7 k; N1 x* A
  31.     while($row = mysqli_fetch_assoc($retval))
    ( k8 w; j0 Q! y5 Z
  32.     {
    7 y  J$ }- ?- m$ }) C5 m* Z+ o
  33.         $id =  $row['id'];
    ; V! F& j; t6 @
  34.     }
    : x+ v* p1 ^/ G: n0 g4 b. w6 L
  35.    
    + Q/ P4 r3 Z0 ?! k7 v
  36.     if($id > 0)
    5 t8 g% d9 v# T% w7 |3 p
  37.     {
    ) v$ p: g8 A% T/ M
  38.         --$id;
    / y9 }- X/ Y+ x' ~2 A
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); . J# @$ F7 {5 e8 p- i
  40.     } 3 f. q' g4 p, \6 U9 d' X( e. U
  41.     # php的文件锁,释放锁
    . ^. R: W. C0 i, d: s$ C
  42.     flock($fp, LOCK_UN); * ^! t) A, Q7 F  h" T% m
  43.     fclose($fp);% R( O! P, M# F# k

  44. / ?9 n' R' I, }) H  }; l
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');1 R, G) P+ q5 @9 `# E) o  E! H# C
  46.     // while($row = mysqli_fetch_assoc($res))
      t5 {5 [1 f. U$ b/ @. v, Q
  47.     // {
    8 A, R* B# L" t6 a" p) M
  48.     //     $id = $row['id'];
    . k' H+ ~/ E: ?, }
  49.     // }5 p8 w7 n- i3 i* M3 g! Z1 }
  50.     // echo $id;
复制代码
& t* b4 o0 X1 N% g* a& T  S
* Z8 o  G" U' N5 G/ A2 g0 A
抢券活动实例:
  1. public function envelopeSnatching(){
    ( c( g5 _3 @" K" [) b
  2.         $lingqu = $_POST['type'];6 q; K1 D3 G" g% D& B& w: D" b& J
  3.         $uid=session('u_id');//用户id
    " m) j3 n( O5 M- V
  4.         if(!$uid){& J' b" u9 v* R. H
  5.             $data['msg']='您没登录,请先登录!';& L& b9 {% O) x  W
  6.         }else if(date('Y-m-d') != '2017-12-12'){8 s  Q: e: H3 G& \; G
  7.             $data['msg']='不在活动时间内!';, K+ L/ F! G- ^
  8.         }else{8 B) T5 N" f# L) y. j! [  ?" p
  9.             $hours=date('H');//当前小时数, P) {0 \) J# @8 K8 h7 P9 f' x8 \
  10.             if($hours > '09' || $hours > '17'){
    % A6 J- M3 _2 c& @2 C" \' C
  11. 5 ?( W7 ^$ `5 ?0 L, j+ f9 \4 Y
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    & o: `' s% P: k! `; x/ E! b9 ~
  13.                     if($lingqu == 1){4 P' r/ t. G5 I9 D; Y& a
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    7 S, V" Q  p1 g
  15.                         if($hours > '09'){+ Q4 v9 v7 U' ^0 |- M4 V
  16.                             $num=mt_rand(25,28);//优惠券金额
    1 j- f' v3 Y. f0 o5 n
  17.                             $id=1;
    6 s$ F. [' @4 E+ u# k
  18.                         }/ a7 s+ ~, i' E: t. Q" S8 U
  19.                     }else if($lingqu == 2){
    / i) U1 U& [+ H1 P! }
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();# e. t# m, R- E4 N0 f1 s9 s
  21.                         if($hours > '17'){
    2 H' B; o8 o% R3 T
  22.                             $num=mt_rand(50,55);//优惠券金额+ O5 M1 a- g$ w0 \& d
  23.                             $id=2;
    7 ?- K8 r; z$ a3 X
  24.                         }
    7 D& B- ?% n! J7 m$ _) G
  25.                     }. j7 G8 P+ R6 i% \, s. t, O
  26.                     if(!$id){$ }8 ^/ W1 j1 u! W( K) F7 q- w
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    # _: w. ]/ G9 g. g& Z: F& i% r
  28.                     }else{: Q4 k0 v. C# h0 P- q
  29.                         if($is_lingqu){
    1 z* B' Y* L- ]; q) K
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    " C0 T( X& O& N! n, _3 [, T
  31.                         }else{
    ( p6 C: h3 V% E0 B3 D; i
  32.                             //锁表
    : D' o( A5 E# P$ Q" m( Y/ `
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');5 y( ?8 g0 U" a. O" ~% W2 }+ l0 i
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();" H5 e! T: x0 j' j' }6 M" n- g
  35.                             if($active > 0){
    ) O& B0 h. t5 v7 U+ n
  36.                                 //开启事务
    " W1 k$ U' J  b* d
  37.                                 M()->execute('start transaction');. h2 b4 E% d1 ^# Z& a
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
      E* @( }4 x0 E* c1 s% l: n
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));3 T0 O: n5 k: B9 P
  40.                                 $members_preferential    =    M('members_preferential');
    ! K; [& R0 j& N/ t* h
  41.                                 //对应投资金额,1 K$ `: R0 X2 A
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    1 g. O% a" g% ?9 x
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    - R2 U0 o0 G  z/ r; v2 m' u
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    + {% q# G8 T; Y
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券" I0 r3 R  t! W$ C" T4 X
  46.                                 if($save && $add && $add2){4 S1 U- \1 z1 g7 N; F
  47.                                     //事务提交
    : h4 ^8 v3 f$ r- X0 l- l- g
  48.                                     M()->execute('commit');! P# _( {" _9 m/ ~; h
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    4 {  y" t9 ^3 ]. D$ X0 n
  50.                                 }else{, A6 r& M: @5 R& W
  51.                                     //回滚7 ?9 m6 @: K9 e( e
  52.                                     M()->execute('rollback');2 \; C# N+ }3 T: P8 V
  53.                                     $data['msg']='未知错误!';1 P6 X, K9 I& j9 g
  54.                                 }. v! z: ]( d) ?  f7 O$ v, X; L
  55.                             }else{
    9 p7 N+ G, ~* F/ x2 \; R
  56.                                 $data['msg']='红包已领完,你来晚了!';3 {) d; P0 w9 Z5 k4 ~
  57.                             }
    - ]* U/ H0 m) x/ D! x6 g- @
  58.                             M()->execute('UNLOCK TABLES');0 j8 |1 n  V; q8 j1 J; f
  59.                         }
    ) h$ h( W9 N9 p2 M$ E# O, O
  60.                     }" f( H9 g2 I6 j. ?: W
  61.                 }else{
    , ~; l) J) S. V4 E! u0 d
  62.                     $data['msg']='非法操作!';7 \! s/ E& G$ Y
  63.                 }. |3 Q) U; z6 {# z
  64.             }else{, f! w. K% E5 w8 k
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';: H( m  O' l$ }) ]( {
  66.             }4 e4 Z. l* i' d  E3 U# @% N2 ], w
  67.         }
    : n$ I' z( M' H0 L4 X7 f; h
  68.         exit(json_encode($data));3 c; B/ j/ `( t
  69.     }
复制代码
6 C/ V9 s  m0 ]# T6 i

4 [4 S  C: S- ~" O" B! ~. f* W; G
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 23:16 , Processed in 0.146478 second(s), 19 queries .

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