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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8716|回复: 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://请求的脚本
复制代码
1 f4 b# u' g5 u7 u' t5 Z( d0 e6 E
Mysql中的锁语法:/ j0 T: M% _1 W2 j% {( i
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
* `' H) u; z# J0 ]UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表, \- z2 j$ F, g. X: ~
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞) T9 w9 _, M6 m) }
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
# ?! c9 z9 g2 x0 w) o, b! ~" N文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
  r! R# t, B! M6 k" G# u测试时,有个文件就行,叫什么名无所谓
总结:
# u# p/ k/ `# S2 D8 d# N7 v) q+ a项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
2 M$ \5 L, V& F# z$ |1. 高并发下单时,减库存量时要加锁3 Y, M, a0 X0 N; r# j  u
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    & i+ N) w3 n6 V7 a: ?% M/ F
  2.     模拟秒杀活动-- 商品100件
    + D, I+ L. p' O& W# R
  3.     CREATE TABLE ta
    0 a* N- J9 `# I. C. H% J& Z
  4.     (
    9 ?6 w- L5 W5 D3 M
  5.         id int comment '模拟100件活动商品的数量'* H6 b+ S9 F& |
  6.     );5 i; k& |" A# M* y% E# r3 _
  7.     INSERT INTO ta VALUES(100);: [2 m& N# [$ T" F
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    $ A: q; `( n3 x4 b0 w6 H
  9.      */ " ~! _4 S( R+ @$ ~
  10.    
    2 ^% n0 d3 R# {* h: y" g7 l- i
  11.     // 关闭错误报告
    & L( I7 X1 C1 _8 s. V
  12.      error_reporting(0); 3 o2 r  a* s$ s3 I4 P" Y

  13. % W. @3 b! F; ]$ j! x) S$ I
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    % v% K  I! Z1 M, t( h' T3 i, J
  15.     $dbuser = 'root';            // mysql用户名
    0 R- j0 r  h! V1 d3 Z2 X* f
  16.     $dbpass = 'root';          // mysql用户名密码2 ~  \# W$ Y9 X- {: w& O
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    $ Z9 Z3 m, H6 F7 m! }3 E! T
  18.     if(! $conn )5 b" T: S2 Q; S
  19.     {
    5 J9 z' \% `9 ]* q
  20.         die('连接失败: ' . mysqli_error($conn));6 `) m  N3 p# S9 B6 o* Y2 b( U
  21.     }' _) c* y& }4 @! Q# k! Q9 q
  22.     // 设置编码,防止中文乱码
    7 B: y; m6 I* ?* q, o' M3 A
  23.     mysqli_query($conn , "set names utf8");6 S8 z4 z; V: N/ A) j2 i
  24.     mysqli_select_db( $conn, 'temp' ); 7 p( o: |1 j  T' G. s4 e4 u
  25. " y2 q' G' N4 f
  26.     # mysql 锁 6 ?3 p) B& X' v0 e! S- g+ h
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 & }8 Q, P* m: D  L6 P1 J  w+ ?
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    3 a3 U; m( c' ~. C. f& R# P7 K
  29.     $id = mysqli_result($rs, 0, 0);
    ) {$ Y* g: D7 L! t* r8 c' w+ u
  30.     if($id > 0)
    ; U* y& K- P2 u3 ?( s; G
  31.     {   ^6 @/ @9 I  u& k) G; v. R
  32.         --$id; 3 {1 `" i" U+ X" I% q2 n
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); : v, j9 U. s! t6 F
  34.     }
    ' a& ?1 K1 P; M0 z. R, q) [0 W

  35. 0 e' k) `3 @3 H! Q5 y% A; J
  36.     # mysql 解锁 ! O2 G$ r: \& A: }$ G' H
  37.     mysqli_query($conn , 'UNLOCK TABLES');3 x& Q+ _7 L# g
  38.     //查询解锁后的id值
    / _6 x, q8 a. L" R: T, @& |
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');' H+ D% \- x* k- b( L; \
  40.     // while($row = mysqli_fetch_assoc($res))$ a# f# K& r" c* Q9 F
  41.     // {+ N' F2 [) e! s2 O
  42.     //     $id = $row['id'];
    & N8 g6 ~" H; E( J4 x3 G
  43.     // }
    " ?+ ]/ e) z$ Z( b, p6 N
  44.     // echo $id;
复制代码

* E" i. Z0 C, G& p; \: r5 Z8 A9 |9 ?! A4 g: j* I
# a/ G: u& u" H! W6 r8 ^" N
PHP文件锁示例:
  1. /*
    2 M* s) b. H/ l; [3 ?1 d/ O
  2.     模拟秒杀活动-- 商品100件% N6 }1 i" ^/ }
  3.     CREATE TABLE ta, c" l, Z% R1 w6 G! t8 Z7 w, l
  4.     (0 ~2 z- d* B8 I) ~% W7 w: R/ O: L& a
  5.         id int comment '模拟100件活动商品的数量'* S5 u- T  d: N% I: [7 N
  6.     );
    ' Q, R, b8 \; v0 ]
  7.     INSERT INTO ta VALUES(100);
    $ t8 J: ]+ a1 i# E" W0 M& T
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件% L% \/ J9 e- |! h! J' k
  9.      */
    2 b, Z0 j# u. ^8 b+ a6 r+ D. W
  10.    
    9 Q: c% i/ p: m1 K
  11.     // 关闭错误报告3 |0 D3 f9 f( e( ]( @. ]1 L
  12.      error_reporting(0); 9 y  ]+ Y3 G$ ~0 p$ `, L8 o
  13. * _1 ?$ R6 W; U. n1 l/ X  ^
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址, d8 e3 G  u- q! g/ ?8 R$ {
  15.     $dbuser = 'root';            // mysql用户名
    8 ^9 R, ~5 d3 H/ W
  16.     $dbpass = 'root';          // mysql用户名密码
    - |# J8 @1 v, Y
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);+ |2 e( R6 V, Z7 t: G
  18.     if(! $conn )! x- G  C/ m6 \8 Y0 k
  19.     {
    8 ^* a* T  I! b  ^
  20.         die('连接失败: ' . mysqli_error($conn));
    - E& F* \  Q/ u. A' Z2 x) T+ k% N
  21.     }
    0 M3 D6 [# n* b, j) E9 P/ ?6 j- P
  22.     // 设置编码,防止中文乱码
    # m' ]% I/ E# h' V$ X
  23.     mysqli_query($conn , "set names utf8");
    9 n, y' I$ D7 f, F* G- i
  24.     mysqli_select_db( $conn, 'temp' ); ( r- t2 l. Z2 M% I0 M7 l% m

  25.   D; P, x8 l1 x% u" y% N
  26.     # php中的文件锁
    8 G1 `( R  W/ Z
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 3 j* L2 |. z) M( v/ q" P) f
  28.     flock($fp, LOCK_EX);// 排他锁 ' y4 b( P$ |4 S3 |
  29. ' B9 K  D# `6 R! e/ o0 v1 c
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    * L; I4 U" @1 W. _
  31.     while($row = mysqli_fetch_assoc($retval))
    . S) B8 z- R" ~; z
  32.     {& ^5 L  r  L8 V" G: E% P1 N
  33.         $id =  $row['id'];
    # \2 L: K- j3 i# ~
  34.     }
    6 M/ A0 e* y' b4 `! d
  35.    
    ! \0 U8 u9 f6 u; `! i$ N
  36.     if($id > 0)
    $ u7 R1 V7 q* n" K
  37.     {
    ( K+ T" ]9 \# V/ o
  38.         --$id;
    & {: V% t! i7 |! j8 W
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    ' \' f" \$ \. b, f7 M
  40.     } . k" u" e! Z0 P
  41.     # php的文件锁,释放锁 8 H. u: G5 k; N9 P1 K7 F
  42.     flock($fp, LOCK_UN);
    ( O1 q3 }  r3 m, v1 k0 k
  43.     fclose($fp);
    ) k' k) O! E/ P+ C

  44. 1 G) C" o3 |+ j0 c( ^% }* E
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');5 ?( ^% D2 L' e( ?4 o$ K: m
  46.     // while($row = mysqli_fetch_assoc($res))2 N0 J3 F. T& X0 h1 N5 F; R
  47.     // {' }/ W  L1 Q& K1 {9 [
  48.     //     $id = $row['id'];
    7 D+ ~  }, Y3 e, a
  49.     // }
    % V8 I* y1 J3 w/ t6 ]# w1 S
  50.     // echo $id;
复制代码

3 j/ f* G1 n& `( c; K% S. ]) X2 d+ o- i2 y6 r* X; q
抢券活动实例:
  1. public function envelopeSnatching(){" q* D) R$ V3 I3 l! w6 M
  2.         $lingqu = $_POST['type'];
    * l. x* }/ q: l. g7 ~/ `6 `) _' Y
  3.         $uid=session('u_id');//用户id
    ! |% ]: f* O8 k
  4.         if(!$uid){. Y% i  A- b9 F) p. T% E# c, d
  5.             $data['msg']='您没登录,请先登录!';! J4 N& a" x4 y$ b) M4 ~
  6.         }else if(date('Y-m-d') != '2017-12-12'){5 u" K. Q  z7 ~. V! f- U
  7.             $data['msg']='不在活动时间内!';
    # @) @9 t8 `; X/ A9 L5 E0 `
  8.         }else{
    1 U" A' i4 c0 q
  9.             $hours=date('H');//当前小时数
    ( {0 C3 a6 z- ^0 x1 E" t
  10.             if($hours > '09' || $hours > '17'){
    / _: N0 E: N$ r1 l- r

  11. $ C- [: n4 ^: `( i& R
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    : Z9 L3 U5 |$ U, `
  13.                     if($lingqu == 1){
    5 j5 z; R7 Q3 B; J, _
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    & M8 l# P) A" v" \4 |" d
  15.                         if($hours > '09'){
    6 f& ]5 G1 U) D- g
  16.                             $num=mt_rand(25,28);//优惠券金额5 f% y9 `; {& R7 d- n
  17.                             $id=1;
    2 ~# M2 g( x# S& N
  18.                         }
    . D0 d) ?6 Q) i7 Z! ?3 \( m  ^, O1 g
  19.                     }else if($lingqu == 2){* T. j0 _. F2 \1 D6 L* s/ h$ I' |
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();- k8 {8 `7 I4 K  O# ]
  21.                         if($hours > '17'){
    " B4 i* o9 O- k
  22.                             $num=mt_rand(50,55);//优惠券金额
    + G% S+ t5 ~" [9 M9 n8 @% M8 @' S
  23.                             $id=2;7 u% o9 C# V+ f* Z+ g+ a. O2 z
  24.                         }/ E5 a* q3 c1 g+ r8 R$ V3 u
  25.                     }
    + q9 C. ?4 I% c0 o3 |0 @
  26.                     if(!$id){1 P! l4 W$ y0 ^6 B
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    - W4 w* ?3 _" {. H9 S
  28.                     }else{! M; X5 v, u+ {2 [
  29.                         if($is_lingqu){
    ( i* u3 a% O1 ~4 z  M* {9 d
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';$ Z$ C0 T* k3 w9 R" h
  31.                         }else{
    / @( R+ K7 s; N
  32.                             //锁表
    4 Z* d2 `7 Y3 J8 n
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');! L* q5 g* c' v* c+ F/ b* H0 i2 S
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();0 S$ t9 q% G; r
  35.                             if($active > 0){
    ( Y6 |0 n- D9 x6 f
  36.                                 //开启事务
    ! [( O! a2 L6 o8 |: s! M
  37.                                 M()->execute('start transaction');
    " d3 [1 X! z- f/ L7 Z
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    # ~- m  {8 @/ ~$ M; R& z! V1 O; y
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));( a9 f5 _, y9 B6 {  P: j, T5 ?
  40.                                 $members_preferential    =    M('members_preferential');
    0 Q5 U1 ~% T* G
  41.                                 //对应投资金额,
    " v9 O, X! k" v$ o* X0 x0 r3 M
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    9 ]% Z0 G7 a2 \% z
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');! e' L, P& o9 Z8 G1 p, a& ~5 q
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    3 d# h& q9 T/ Y
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    . R6 |/ `. D  W
  46.                                 if($save && $add && $add2){8 G$ a* z9 E, G3 T
  47.                                     //事务提交
    0 k+ b  e$ k( a& {9 @6 ^0 M% N
  48.                                     M()->execute('commit');
    / \/ l1 {+ o! ]. ~5 @1 I2 [
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';/ k# f9 q- q! n% U. q
  50.                                 }else{, _* ?  l9 H! y. r- @* C- s8 c9 y
  51.                                     //回滚6 b8 M" `4 ]' C3 S1 T% w, \
  52.                                     M()->execute('rollback');
    6 r( i' r7 K+ D8 H7 R7 G9 ~3 |
  53.                                     $data['msg']='未知错误!';
    6 d3 O6 U0 C* t! X7 H$ a  w
  54.                                 }
    3 i- }+ ~2 s, _; r
  55.                             }else{2 L  G4 Y; v: R7 F; U5 l1 q3 m2 F( R
  56.                                 $data['msg']='红包已领完,你来晚了!';
    - d. A* c. ?3 ^
  57.                             }( f) B& |2 \$ H- d1 P
  58.                             M()->execute('UNLOCK TABLES');, P4 r' A4 p( _
  59.                         }$ I+ ?0 h) u+ e$ W# W
  60.                     }+ z& u4 P0 l- h$ ?$ R0 }" [# s' y
  61.                 }else{7 q! e! o) u+ p* `1 U& U
  62.                     $data['msg']='非法操作!';) \" s- O  y0 B0 E* i$ {7 J# z' U
  63.                 }
    + i3 Z6 E' G- j0 ^' J
  64.             }else{) h0 J. ]3 K0 O* z, \6 y
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    7 O* c8 Y# a+ r- [* s/ R2 S  j5 q
  66.             }% q* x! {8 V0 w: d
  67.         }
    7 _8 ~7 T' v  w2 ~# Y
  68.         exit(json_encode($data));: `5 L* W$ W  x; k- T
  69.     }
复制代码
; t0 s  D6 `, ~) o9 n% y2 a

$ H+ @9 X. c- u* z8 }5 i
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-4 09:30 , Processed in 0.064279 second(s), 21 queries .

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