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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9328|回复: 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://请求的脚本
复制代码
( {5 l* z# D, j
Mysql中的锁语法:
2 A  ^  `) Q$ [, F/ {, ?2 fLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
/ i- I8 X9 z+ ?UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表4 G7 K/ }1 G7 a% a' c! O
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞  D  o6 s) Y  I' S$ Z
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :; \/ Y) S. p& T' U* a" `6 _
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。& I9 q0 l9 g4 ~8 L9 P
测试时,有个文件就行,叫什么名无所谓
总结:
5 p: \$ j5 _$ g. U# v: V5 s  ^项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:; M/ F) B5 M. M% |: k8 O' V
1. 高并发下单时,减库存量时要加锁
/ j' M8 E& Y. o% y  j5 n5 w2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    ) g5 a0 U* }3 S6 I
  2.     模拟秒杀活动-- 商品100件
    - N! R) E' }, W6 K3 K' Q
  3.     CREATE TABLE ta
    4 L  E/ }3 [& I$ h4 q" }
  4.     (# L; G% O" j+ w( e/ L+ M- Q+ T
  5.         id int comment '模拟100件活动商品的数量'% o0 m9 g2 l4 _5 \0 @4 d
  6.     );! T3 M0 R8 s* N. B$ ^
  7.     INSERT INTO ta VALUES(100);' N; h' y9 d6 H* _! m
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件* w& B* `: c9 j  ?& K7 Q0 C# d
  9.      */
    % c# o, c0 m) r+ p* E; H' D
  10.     ) ?9 x6 s! ?$ P) a% ]( S; g
  11.     // 关闭错误报告' \  F% Y( i! H* `, \" y% A9 N
  12.      error_reporting(0);
    & }% i- A6 i/ v6 T

  13. 4 S" q+ B& R3 D$ `9 W% ^
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址% l+ B: q. h; J% J8 _/ j
  15.     $dbuser = 'root';            // mysql用户名! e; d: U7 e. n, y0 J- k+ l
  16.     $dbpass = 'root';          // mysql用户名密码6 t$ R6 h0 h1 M* y$ E& p4 b1 e5 Y, h6 t# T
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);4 f2 H) N# p. ^
  18.     if(! $conn )
    0 |$ o" P* c9 `, }8 x
  19.     {! b5 I! q2 Q! T. a7 z: p5 `9 B0 |& @
  20.         die('连接失败: ' . mysqli_error($conn));. H0 M. m; F% C
  21.     }5 O! F) q! [9 C. Z
  22.     // 设置编码,防止中文乱码
    ; n0 a' o& j  ]4 s& }* D
  23.     mysqli_query($conn , "set names utf8");  o. M9 Z: F. F. X2 P3 |& L8 g  r
  24.     mysqli_select_db( $conn, 'temp' );
    : r% p' W7 c) f* ]1 R% q% R
  25. 8 B+ m/ }' H  S- a8 T6 u) y
  26.     # mysql 锁 $ B# H9 y* R3 X: |  Y, M& B2 ]8 {8 d
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    8 D. R2 G$ u% _! k* g5 {* k2 k$ _9 d
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); # D( n1 Z3 v" x. t7 V7 R' O# N* b
  29.     $id = mysqli_result($rs, 0, 0); " ?4 G/ G& F! |* x% c) X8 \
  30.     if($id > 0)
      b( J, F1 R0 i
  31.     {
    0 T$ {+ y; N! u  E( n0 Z
  32.         --$id;
    ) ?# `4 x' q" e/ S5 _8 ~( n- F
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    , B) ]/ t; i' T2 H$ ^+ j$ v. r
  34.     } ' s- s+ B3 u% x( H& ]' U

  35. $ P# h' i; g0 [' B2 J9 m% u. g$ B
  36.     # mysql 解锁 7 [4 K, j* [0 R* B+ L6 l
  37.     mysqli_query($conn , 'UNLOCK TABLES');3 R, L& H' g& S, {+ E9 @# `4 z
  38.     //查询解锁后的id值
    # e! z1 R  B4 I
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');7 Q' Z. G2 u" K, z8 ?  Z$ z
  40.     // while($row = mysqli_fetch_assoc($res))
    " {( m! y# `" W
  41.     // {3 O9 X; F1 K7 Q: ~
  42.     //     $id = $row['id'];
      F; o: I8 B& R; u8 c! ~
  43.     // }8 q8 o# Z5 q, \2 Y
  44.     // echo $id;
复制代码
7 y- A2 `# i$ J
2 _3 D6 R$ A+ r( ]( i4 u, q+ u3 K- L
# k6 s  y% f2 c
PHP文件锁示例:
  1. /*. X+ Y9 E! ~" l) g# i5 x
  2.     模拟秒杀活动-- 商品100件* G# H9 E$ N) F5 q# @
  3.     CREATE TABLE ta
    + P$ B; c" C8 I, z
  4.     (/ D2 Y, q* V4 k. U3 E& f+ p
  5.         id int comment '模拟100件活动商品的数量'
    + G$ V, d" q( g2 T
  6.     );
    . A' ]8 y! o  C  ~. F5 f5 |
  7.     INSERT INTO ta VALUES(100);
    8 o' e( M5 O) m/ o- ~+ r
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    . ~: W8 i: V* B, d; ]
  9.      */ ! N/ c) F/ p: s; ^' M
  10.     3 F5 S$ b2 p9 s/ Y: V; l7 W5 g
  11.     // 关闭错误报告
    5 }  \. W) J: n1 {: w
  12.      error_reporting(0); ! ?. N! }$ I4 a! y/ t

  13. : ]/ M- Y. _6 h) d* X9 ~  V( W
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址% B% d5 A, ?0 k6 k1 G
  15.     $dbuser = 'root';            // mysql用户名
    7 m, H$ s- m' o8 }$ T
  16.     $dbpass = 'root';          // mysql用户名密码$ Q4 s( n9 E7 @) Q5 o6 g
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);# r5 X3 x0 b. ?3 u! t. G/ C8 @
  18.     if(! $conn )  d0 ^# h% G' l. u9 n1 D
  19.     {
    : ]! t" C" a8 |. ?- }$ Q
  20.         die('连接失败: ' . mysqli_error($conn));
    0 Y7 ?9 a6 s0 N7 b5 I
  21.     }' F; v) D3 F0 N* }; r
  22.     // 设置编码,防止中文乱码! v9 R3 v8 V! H; F+ [0 k6 r
  23.     mysqli_query($conn , "set names utf8");- {, m0 @/ ~2 v/ _7 r7 z+ T
  24.     mysqli_select_db( $conn, 'temp' ); # k- y$ k2 L4 B% N1 |1 G+ V
  25. 5 K4 C( n8 J# E: s3 f+ }& @* `. g
  26.     # php中的文件锁
    5 |+ m  j: ^1 i- I& t8 \
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 ! _' F3 v! E  \$ S* [1 R/ H# A
  28.     flock($fp, LOCK_EX);// 排他锁 - T- \3 [' f. l) }& M

  29. 0 T: K9 @) N' Q: a6 R
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');   i% T6 d5 ~9 ^
  31.     while($row = mysqli_fetch_assoc($retval)). R4 Y( k# d) s7 _/ f- q1 r0 O% K
  32.     {
    8 q$ Y, y4 N8 A" g7 Y# N. s" q( `
  33.         $id =  $row['id'];
    0 V) L5 u9 }7 z3 f% D) q
  34.     }
    9 L, z! b* I/ J1 ~" B4 W4 @! J, i
  35.     + `& r% k4 a. n* d, a
  36.     if($id > 0) 2 D  G& @5 ?9 b$ i( L  d2 w' p
  37.     { , Y, `, e3 H, U: ]5 H" h5 p
  38.         --$id; / m( S, ^5 ^# h  O; `$ _$ R& h8 p
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 7 m9 Y9 p0 G5 E8 d
  40.     } 4 y  G1 x, S, a
  41.     # php的文件锁,释放锁
    9 i$ L" s, b; }$ y* [; x
  42.     flock($fp, LOCK_UN);
    3 E6 {* n2 H% c% v5 Y$ C  i# L
  43.     fclose($fp);
    & }# c1 Y3 r( D  P7 w+ T. ?
  44. 5 ^+ d. w2 p( v+ R
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    " P; D! p. K4 {5 U0 k
  46.     // while($row = mysqli_fetch_assoc($res))  }8 M* u+ P8 N. j! Q
  47.     // {2 U! k1 A! ^% u( T0 u& W
  48.     //     $id = $row['id'];0 ?- c; t2 A5 L. u, U6 N
  49.     // }) G  z' [2 |( d6 e( Y8 X# y' R
  50.     // echo $id;
复制代码
0 v, I: _4 c8 W( F
$ f4 ~- ]6 O& \' W/ g3 n
抢券活动实例:
  1. public function envelopeSnatching(){
    % s# w9 A* P1 G* P
  2.         $lingqu = $_POST['type'];
    9 {. U1 m& K3 R
  3.         $uid=session('u_id');//用户id
    % J! @. x0 e; c
  4.         if(!$uid){
    2 y0 @' g* O0 z* U: G4 s8 O1 s
  5.             $data['msg']='您没登录,请先登录!';
    ; w8 e1 T9 I- X+ z- i3 ^
  6.         }else if(date('Y-m-d') != '2017-12-12'){) }" y2 x, i2 \+ d$ v  ^4 E
  7.             $data['msg']='不在活动时间内!';
    8 u6 ^2 g; R0 ^4 Z8 V! [% H; M1 N
  8.         }else{" b2 f$ i) `; u' _0 J
  9.             $hours=date('H');//当前小时数# h2 ^" I; z+ o+ l
  10.             if($hours > '09' || $hours > '17'){$ I% f! r3 e% F/ V" J

  11. # ^6 L5 e4 Z8 L- K- J7 K' F
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    ; R5 b, u0 K; v
  13.                     if($lingqu == 1){% `6 _5 i! f) S* n/ g, e
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过7 m) |# P3 ~% ~) b
  15.                         if($hours > '09'){+ u, D, _! r& G. Y/ v5 B
  16.                             $num=mt_rand(25,28);//优惠券金额
    6 v1 K. s4 \! K0 r5 ~
  17.                             $id=1;( `/ E7 y9 T+ F- C. r9 Q
  18.                         }
    ; [# a3 L, y9 m
  19.                     }else if($lingqu == 2){
    * [$ l  r; u7 U. b% ]6 h. j; c
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    0 o' ~) c- b* [5 r: ?4 l
  21.                         if($hours > '17'){  D3 c9 r# X" t9 ^/ z# _# i
  22.                             $num=mt_rand(50,55);//优惠券金额
    : E1 A6 x% c5 }
  23.                             $id=2;$ `1 }7 n5 N3 l1 q
  24.                         }
    : ]* W0 i- h8 M, A( s. ?8 K! [
  25.                     }9 N8 j! O/ G) @
  26.                     if(!$id){
    : x  W: B  q  ?. `, @: t
  27.                         $data['msg']='时间还没到,晚点再来吧。';, f2 u( g: H0 o! t
  28.                     }else{9 a$ j% |% D/ y+ ~$ b
  29.                         if($is_lingqu){
    - M8 A' x) X; V3 x; }! D- j
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    3 F' k& e: A9 s" y3 H7 a' _  R, Y7 U
  31.                         }else{' [  [! h1 h' o0 X$ a3 J9 w
  32.                             //锁表# Z) J) T) R9 l# @* Y9 b: C% D
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');1 U% |1 q+ W* m) R
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    3 B" m- j3 J9 P  ~* o1 H
  35.                             if($active > 0){
    8 ~8 j" [) g) ?& O
  36.                                 //开启事务& c- Y$ C( q, ?
  37.                                 M()->execute('start transaction');
    $ B  P6 z2 B; A& I, Y
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));6 w/ C' B' x* g- J+ X& l0 L+ I
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));+ I# z: @. z# g, |+ |! u: h
  40.                                 $members_preferential    =    M('members_preferential');/ D$ [, f, I3 A; z- q
  41.                                 //对应投资金额,2 w; ^) `, a5 a
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
      d/ N" [4 J8 }
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    * ?/ F! q* `7 G9 p1 c
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间& \9 g" K* q4 R  C2 t7 S7 ^" g
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    3 \, `! L) Q) u5 N$ O
  46.                                 if($save && $add && $add2){7 X8 M  G6 H3 I  Y' g
  47.                                     //事务提交
    # E9 [" X) b$ e5 n6 f
  48.                                     M()->execute('commit');+ L! C2 [- r7 e; m" \
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    % ]  s0 Z( Q% B
  50.                                 }else{' c) {6 i: `/ I" `3 m7 N
  51.                                     //回滚
    / N6 \7 I' L% S. S
  52.                                     M()->execute('rollback');2 t' `3 z, k# w4 |/ g/ M0 v
  53.                                     $data['msg']='未知错误!';
    8 t4 q( s8 r# i8 _5 S) s  M7 A7 j
  54.                                 }
    ' ^7 n! I8 G- @* k; w- U( X
  55.                             }else{0 q: V9 S$ {$ F
  56.                                 $data['msg']='红包已领完,你来晚了!';; \1 {9 c( n' F2 X* e
  57.                             }1 ]* s" e' i8 o) G( P5 R
  58.                             M()->execute('UNLOCK TABLES');
    8 t/ ~, w, U: M, h
  59.                         }
    3 ]( I  J, F% d7 O) e+ d# R( D, C9 X
  60.                     }5 O) Z3 |& z9 X. I' v
  61.                 }else{
    / d$ a) s1 {  a3 e( x% h2 d% v. n
  62.                     $data['msg']='非法操作!';1 p/ m5 c. \. Q, Q$ m1 k  [/ U
  63.                 }2 h4 G( K* {* f
  64.             }else{
    # X7 f9 u% Z  z+ ~" x
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';# z9 Z! N8 Z, e( \7 D' i" d
  66.             }2 G; C9 Y; V/ G
  67.         }6 \) P7 E. ]: q: k
  68.         exit(json_encode($data));
    3 z# y& P& Z& j& F: G3 \% f
  69.     }
复制代码
: f: `1 M! c8 {

( E% L( L/ L  l4 @
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 07:09 , Processed in 0.054993 second(s), 19 queries .

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