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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 5724|回复: 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://请求的脚本
复制代码
  D; k0 R* j9 C4 W# k
Mysql中的锁语法:
- C/ ^, s8 }  ILOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
% Z" b2 ?0 }  Y0 C) M5 `  IUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表5 o) A& G  k( _- u8 A" Z' c3 a4 j
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
; O( d: Z) |$ F' U注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
0 ?7 a" X6 f) g文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。' g- i# `; s6 G4 Y
测试时,有个文件就行,叫什么名无所谓
总结:# y; E/ r0 y+ H+ y/ q
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
. h. U0 K, q  J) Y7 [3 ~# S1. 高并发下单时,减库存量时要加锁
. Z7 |, C5 r9 V* d4 E2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    & F& ~- R  F7 l7 t! `# ]
  2.     模拟秒杀活动-- 商品100件$ `& }8 R0 E& b5 b* A/ R0 }5 R
  3.     CREATE TABLE ta
    ; t: P; ^# R7 Q3 Z
  4.     (8 |$ m+ f4 B- ~* k' ^0 ]3 o
  5.         id int comment '模拟100件活动商品的数量'
    ; [9 d$ R& A0 M* Z0 e& o, I5 n3 z
  6.     );( [# j' E7 G8 f5 z! f. [
  7.     INSERT INTO ta VALUES(100);
    7 D* X0 c) h0 V9 M
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    & o$ ?1 f7 p. j; t) k% q
  9.      */
    # h% {+ W4 z$ k1 @, W
  10.     $ ]9 D1 u% R2 ^, n2 E: a
  11.     // 关闭错误报告" f) p/ z7 D& ]. I1 k* q7 K
  12.      error_reporting(0); & u, h1 _8 [  S7 M8 n: N* ^; c
  13. 7 d6 x/ i6 p: y* y4 w* ^
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址2 @; C. P" t* g0 A) N6 p' _% d6 {
  15.     $dbuser = 'root';            // mysql用户名2 w% a! j8 q" B' s' l
  16.     $dbpass = 'root';          // mysql用户名密码2 t7 [7 [9 v  S  r$ |
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);5 j1 p: c# I8 \: P$ `; K* Q
  18.     if(! $conn )! J# q- b# C/ B; ]0 V4 Z7 `% P3 b
  19.     {
    # ^2 E( m2 S% U
  20.         die('连接失败: ' . mysqli_error($conn));  N& Q. ]/ J9 b" e/ E4 @; M5 G
  21.     }2 L7 S/ `% X/ Y( `
  22.     // 设置编码,防止中文乱码& p7 ]. c- H% X; W- v4 c
  23.     mysqli_query($conn , "set names utf8");
    $ }" e5 S2 D- l8 E8 Z
  24.     mysqli_select_db( $conn, 'temp' ); 3 a1 M  W- q" o6 Z. C2 I
  25. 0 T1 G$ R* S, \0 u& r0 c6 j
  26.     # mysql 锁
    ; F8 W& u6 B+ Q# L8 c  I
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    # C- Q" D& T! f) W$ w' h7 I" F
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 5 u& K5 s# N9 o6 K/ G4 i9 p0 t1 P% I
  29.     $id = mysqli_result($rs, 0, 0); , {6 u- b2 f8 H' |0 E. T$ L
  30.     if($id > 0) * X+ }6 \3 X, U' \( r% \6 Q$ r
  31.     {
    . V% C% L( v4 ?0 A6 ]
  32.         --$id;
    ) Z- M  h8 f. J. c# X
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    4 D" M. B6 w; p; i  t$ M3 E) K
  34.     } ! r9 n% Y) d5 D4 R: I$ u# o
  35. : K* t9 K8 K0 L9 c
  36.     # mysql 解锁
    ' j- a, W: w1 j
  37.     mysqli_query($conn , 'UNLOCK TABLES');! Y/ q) d& b0 g/ D
  38.     //查询解锁后的id值9 b; n; X8 J* J
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    9 r; z; ^* x2 q* l" L- l) T
  40.     // while($row = mysqli_fetch_assoc($res))$ b: p% F+ {) ?' k. W2 ^
  41.     // {/ i1 [% m+ ~4 W5 q* r: B
  42.     //     $id = $row['id'];4 `$ L# f8 d2 a
  43.     // }
    6 \6 }/ A' Z1 j) }& J* T
  44.     // echo $id;
复制代码

6 ~( c; h. `  {, b) |; W6 h  e* M
  O- V! a1 w) Y
! b' g1 l" C* N2 f
PHP文件锁示例:
  1. /*
    / ^0 b* L- \, ?
  2.     模拟秒杀活动-- 商品100件7 j" c6 M0 w: X/ x
  3.     CREATE TABLE ta" w( [; {9 J# X- E7 c
  4.     (
    ) k7 Z; y$ C+ n  G1 ~. d2 q
  5.         id int comment '模拟100件活动商品的数量'5 P. l2 m& Z+ E% j% O  S
  6.     );" W0 ]+ M3 N9 D& ]4 S/ s
  7.     INSERT INTO ta VALUES(100);0 H: ]3 \! K& V0 K7 o1 `
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    " d/ T; f+ t# f: g+ d
  9.      */ / @9 b% y+ B4 O5 S; V
  10.    
    * j$ P/ {. u: O) H5 J2 |1 j5 O$ b9 |
  11.     // 关闭错误报告1 X3 j1 S" S! x* }' d/ B& a
  12.      error_reporting(0);
    & F$ m" m. D' B
  13. 7 ~' I* c* {0 f1 e) N, I: M6 W4 v
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    + ^, c, h7 R( R& D' D3 x, `! H7 Y) U
  15.     $dbuser = 'root';            // mysql用户名
    / z+ \% e+ L0 v- t- e; x
  16.     $dbpass = 'root';          // mysql用户名密码
      r! T' i9 z! ^' B" K
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    * v$ U0 U- ?$ \' I) R+ O( Z+ B
  18.     if(! $conn )
    3 G7 m1 @. [/ G2 z
  19.     {
    $ G4 k' I! [, ^) V) A
  20.         die('连接失败: ' . mysqli_error($conn));
    # _- E/ [" [. T' f; D
  21.     }
    * N1 E; i/ Z2 M- B5 {; X  g
  22.     // 设置编码,防止中文乱码5 g( J$ J7 B" @' k  ]
  23.     mysqli_query($conn , "set names utf8");* B) `- Y- U$ w$ ~! \
  24.     mysqli_select_db( $conn, 'temp' );
    4 ?: p4 q& a( @# |: ~7 y
  25. 8 U# V! l1 w; G! M6 A0 D, @
  26.     # php中的文件锁
    0 B7 ^: M2 a# e
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    4 M: x5 J3 g, [( O8 J/ I  z
  28.     flock($fp, LOCK_EX);// 排他锁 4 [* }$ N2 H3 A' o9 H8 Y

  29. ( G6 ^9 e+ e6 N4 B' j* S" d/ |7 t3 `+ L
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 5 I% c5 x' v. x) K( ^# e5 S: E
  31.     while($row = mysqli_fetch_assoc($retval))* ]9 T1 b3 V* V  K6 c
  32.     {
    7 O% E4 w( ]- Q, @
  33.         $id =  $row['id'];) c( h) s) S: n6 k8 L
  34.     }
    & n4 W0 t% S9 u/ J2 h% [7 u9 r/ f1 g
  35.     4 _8 b) ?/ v2 u1 _, \
  36.     if($id > 0)
    8 n2 W' Q+ c/ Z, j& n# X
  37.     { 3 c6 x! f* T$ C' c! p
  38.         --$id; 1 q+ [. I( q! Y$ [$ F: K, |( q
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); + C7 E& C- @) p$ d% Z9 {  A5 y; S
  40.     } % W' t  {- o8 G$ A5 K  F
  41.     # php的文件锁,释放锁 & t) a4 B( }# F, L: G, f! k# i
  42.     flock($fp, LOCK_UN); 4 L8 m3 J$ D5 M; p7 j, N, T  p9 }* L
  43.     fclose($fp);
    & T2 n, [: L2 f+ |2 `* G! ~. ~

  44. 4 S. |5 m& X  f7 {2 q
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');% t' }( C1 @. k* C! ~8 j4 q# T
  46.     // while($row = mysqli_fetch_assoc($res))
    3 I# f: B# g4 d: q
  47.     // {
    ) L: v; @: H2 [
  48.     //     $id = $row['id'];
    ' P' S7 D7 V3 e" d) d+ d
  49.     // }9 N, U3 }) U, {' e: t3 H4 Q' r; J
  50.     // echo $id;
复制代码
& d4 r, s- [4 h9 u6 r1 r

$ R* d; g2 Z# X; R7 R5 k8 ^
抢券活动实例:
  1. public function envelopeSnatching(){) M7 D/ q$ J5 l/ X5 [  }: ]- {
  2.         $lingqu = $_POST['type'];' \5 l( i- l3 l' f
  3.         $uid=session('u_id');//用户id
    . u/ ^5 c- M" `* m1 X4 G
  4.         if(!$uid){
    1 z+ C1 l2 G- B% K. P" l
  5.             $data['msg']='您没登录,请先登录!';4 d( ~! x7 ?/ D( e+ F8 r' e
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    - A* d  C& b9 S$ q
  7.             $data['msg']='不在活动时间内!';
    + M* {: m! X- B* S( l, G, a
  8.         }else{+ q7 _7 P6 d9 a# y
  9.             $hours=date('H');//当前小时数
    * g$ i' ]6 b* _( B4 w& G, u
  10.             if($hours > '09' || $hours > '17'){1 v- S8 o) B/ H  t6 |+ D3 [
  11. 8 V" B* L, i+ F
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的$ k9 {2 T: I7 f" h. U  m' u
  13.                     if($lingqu == 1){" \$ u# c- q6 G
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    ' ]" q$ Y2 M: n0 o# R' m. K/ N
  15.                         if($hours > '09'){0 S/ J! s% f# G2 f8 X: S
  16.                             $num=mt_rand(25,28);//优惠券金额) Z+ C" I3 V/ v' l8 ~
  17.                             $id=1;* Q) g1 Y0 P1 R) y
  18.                         }
    & h- \, k! L. c4 u- _7 t0 _' c
  19.                     }else if($lingqu == 2){
    2 Y' ]% q# x# O) [' k! ]. Z
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();5 c+ A. ?" O& `9 ?' J
  21.                         if($hours > '17'){% S" H. ^, C; Z1 G; N: R3 g% D
  22.                             $num=mt_rand(50,55);//优惠券金额
    4 G3 {) _- P! v1 I) l
  23.                             $id=2;5 G: G/ E* b- ~  {; s. q. d
  24.                         }+ T0 I- w4 D. |% k) t& r2 t, {- F5 s
  25.                     }9 P+ Q1 Z* \! {" Z2 J! ]6 D
  26.                     if(!$id){
    , O6 u5 ^% Q! m; |
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    : m) }$ J! T9 I$ r3 Z
  28.                     }else{. n! Z6 S# @% ?5 @) u; H
  29.                         if($is_lingqu){) g* L9 k# }! u9 U- `2 K. G
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    - m: F8 r8 O# M4 r
  31.                         }else{
    . T2 z& C$ b5 `% w8 T
  32.                             //锁表" y$ o( v) i5 T
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');* O+ ~) ?2 n8 W: ^4 a) T
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    6 a* c% t* J2 A, F7 E
  35.                             if($active > 0){- @* h8 m+ Q: w
  36.                                 //开启事务
      v7 ^" O( D% E( V/ q
  37.                                 M()->execute('start transaction');/ t4 B8 f- B3 q5 W+ ~
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
      H6 `2 x) ^$ m. h" J2 N
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));. i& D9 _0 r4 V
  40.                                 $members_preferential    =    M('members_preferential');5 E+ b$ N0 K  C) W- P
  41.                                 //对应投资金额,; _; d; H. t$ R* e
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));/ i2 N% M6 v' f
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    3 F# `+ g6 s$ W2 q  {$ I; {
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    6 U' W( ~2 L- y! {6 C; `
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    & U0 S1 u7 X+ @0 O* _4 ~
  46.                                 if($save && $add && $add2){1 \% K: ]0 ]% X+ j3 _
  47.                                     //事务提交# @- Z5 {7 ^* W$ Z( C1 y5 ~# L
  48.                                     M()->execute('commit');' N+ B4 x9 m: Z) @1 D9 P; ~  v1 _$ X
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
      |. I1 K- W* c' v5 |- s0 R
  50.                                 }else{( T$ p3 p( x1 m) ~
  51.                                     //回滚
    ) }; I# @6 u# f/ E3 q
  52.                                     M()->execute('rollback');
    + ]& G# v" I9 n" h  h
  53.                                     $data['msg']='未知错误!';
    4 \9 ?9 a; Z  @6 @* b0 \
  54.                                 }, t! N* q4 ^' q& U' k
  55.                             }else{
    , N# \/ @  X: u/ j/ u) f
  56.                                 $data['msg']='红包已领完,你来晚了!';
    . f& y; q0 m- |5 R
  57.                             }# ]* _" v' k' P$ [  P/ W$ I
  58.                             M()->execute('UNLOCK TABLES');
    7 \+ u+ e( ~3 G. v
  59.                         }
    3 h% s# b" Z5 h! o& U$ D- C8 C
  60.                     }
    & ]/ o, v/ v! m* L% [' H  P
  61.                 }else{
    ! A& z( i8 f3 U! P+ v: g6 s
  62.                     $data['msg']='非法操作!';/ E, m0 d* E6 G
  63.                 }
    % z. P% T' l" T5 f! L
  64.             }else{$ D/ Q1 M6 b# S& G
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    6 g# O4 i: S0 V  ?7 F
  66.             }
    # k3 d- ^) f% h
  67.         }& c7 E! ~- `+ R
  68.         exit(json_encode($data));2 I# Z2 U$ I5 c  F. g3 ~9 P
  69.     }
复制代码
/ k! [0 {* u9 b# R; f! ^
( D9 V3 s# E* ~) q+ I# i5 b  S
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 10:17 , Processed in 0.098323 second(s), 20 queries .

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