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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

3 r+ e6 ]8 f  b. D: E" o' v
Mysql中的锁语法:( J* N; @6 K/ H+ m! Q! W
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】2 W2 z3 M$ Z: Z. ^" R
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
, C: ?, q& P6 T" M+ jWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
2 b0 Y& q- R4 N# ]  n5 z0 X7 i9 G注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
, E7 D% `3 O4 g2 f5 ~文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
* R; P1 I1 p' R测试时,有个文件就行,叫什么名无所谓
总结:2 S4 t$ [' j5 f
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
/ w+ Y# ~6 I, h$ F4 b5 b! A9 x1. 高并发下单时,减库存量时要加锁# S7 i+ Z; O& S; u8 B* S1 X
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    $ C0 O& ]9 o2 ~, y- {6 \0 A8 B
  2.     模拟秒杀活动-- 商品100件8 p6 y9 K5 _8 }
  3.     CREATE TABLE ta
    $ m7 H% J- O8 U9 c3 h; {
  4.     (
    1 Y% v' B, s- F1 a
  5.         id int comment '模拟100件活动商品的数量'
    ; U* O/ a6 n8 L1 Y
  6.     );% w: O! K9 S( a$ c9 X
  7.     INSERT INTO ta VALUES(100);
    * p1 b  N, ?- Y* A
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件5 ^2 L4 d0 [: G0 O7 @
  9.      */ & [- E* D$ Z  u1 ]4 H( R/ m7 ~" J6 U
  10.    
    . o+ Y3 I# c1 f7 a0 ^( \
  11.     // 关闭错误报告1 M" b1 I9 |& E
  12.      error_reporting(0);
    % m' I$ |) a: w, X5 K6 \, d

  13. 8 M6 C1 z3 L. l
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( L, T3 ]$ P2 D2 |
  15.     $dbuser = 'root';            // mysql用户名
    % z4 O1 c! R& E1 @. o$ I' V0 U2 X
  16.     $dbpass = 'root';          // mysql用户名密码
    ' e: Y% G. @" v% K! p* A$ s$ g
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ( k1 z( s1 {6 I  O7 C, u+ \% z# M6 D
  18.     if(! $conn )/ L, D; E. @$ `: B7 ~
  19.     {/ }) c1 [7 L: z  ^1 S  N
  20.         die('连接失败: ' . mysqli_error($conn));- _0 x/ z, j1 l  _$ x) n& `
  21.     }' I3 {$ C) n- k# i, G9 T
  22.     // 设置编码,防止中文乱码
    / ^. q: v7 s7 V
  23.     mysqli_query($conn , "set names utf8");
    7 c* N" V2 O4 L$ Y' z0 R
  24.     mysqli_select_db( $conn, 'temp' );
    ( ]6 [7 v* C3 Y) h# x
  25. ' {% P: d5 s; C8 G8 S# w7 S# v' h
  26.     # mysql 锁
    $ D; Y- }5 p9 p  ]# L- ]
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 % K& A' S  ^3 T% X: y2 n3 h" [! H0 m) z
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    - c' J+ O* p% ^6 y( h4 W. G' w
  29.     $id = mysqli_result($rs, 0, 0); ; c1 V+ j5 g/ y: M9 W+ X' \
  30.     if($id > 0)
    5 K8 [0 `  w2 T) ^. s2 _; z2 G' l
  31.     { # I- Y' s+ Y! s2 g3 m: M9 X8 K+ V
  32.         --$id;
    % P' t+ X; q& n5 g4 L8 w
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); * I7 x5 k% ?4 M8 f
  34.     } 4 a2 V/ b8 S: L; F: p8 g% G  F7 |/ \
  35.   v" I9 }- p. x5 Q4 R6 e  {: x
  36.     # mysql 解锁
    , {1 ?- v1 r) B5 i2 ~# X  d
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    2 b9 s" X& n# t- R/ v9 I6 k7 Y
  38.     //查询解锁后的id值9 T/ n$ L& |+ @! X8 \; v& o1 f0 q
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ) A7 K7 Y( K  P# k  q
  40.     // while($row = mysqli_fetch_assoc($res))* K8 I' L/ \! m/ T( I
  41.     // {
    0 W% D6 f! d/ o, v; L# \0 v/ d/ b
  42.     //     $id = $row['id'];
    # T% O# }9 m, b
  43.     // }* u. B  [& [0 b  H4 C+ {
  44.     // echo $id;
复制代码

+ [/ _& c  M: |' n2 j" I: o. q
) p- ?5 S  V& T. U# D/ t; q

" Y0 p4 ]1 r% y, W9 k$ i
PHP文件锁示例:
  1. /*
    ! d" D; p2 G# l6 u" M. {% X" K, B
  2.     模拟秒杀活动-- 商品100件" X/ o6 V2 W  Z2 Q( ]$ V
  3.     CREATE TABLE ta
    " Y* i7 c" Q: K9 s, X; V
  4.     (4 {) Q: f* Q+ h
  5.         id int comment '模拟100件活动商品的数量'
    , r' v" O( X! _8 s7 p( S
  6.     );
    - k' H2 @" q# p( h* q& d8 g; p
  7.     INSERT INTO ta VALUES(100);% e7 R0 k. }0 H/ m0 ?1 c
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    % L$ g$ _; Z5 `* o
  9.      */ $ x2 r/ P: g$ Y5 }/ D
  10.    
    * C& M$ J9 V+ l+ v! Z8 i% D5 F, i
  11.     // 关闭错误报告
    , D" x1 F, X. R, n4 F9 c# y
  12.      error_reporting(0);
    # S$ }$ j! X  r, X4 D. |$ W. H
  13. 9 }6 r1 P' r+ b, G
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    # T: O  d& n( O2 x: m. b
  15.     $dbuser = 'root';            // mysql用户名
    7 N7 q: h* ~8 v) D& d% s6 ]
  16.     $dbpass = 'root';          // mysql用户名密码6 A' y, \4 F, d6 P5 J% v
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);9 F+ `8 p1 h; g" o& o' w: {
  18.     if(! $conn )
    % ?& B; j. S0 g- {0 P9 N- Y
  19.     {5 v9 l4 S1 |1 n3 g. M! x4 E
  20.         die('连接失败: ' . mysqli_error($conn));: K4 }# {) i; [$ n( u4 ~  A
  21.     }
    ' f$ S. y9 h& [* c6 e3 P: I3 A
  22.     // 设置编码,防止中文乱码
    1 K( c; u1 J. ^: g& O
  23.     mysqli_query($conn , "set names utf8");- N2 W  M' T. l4 J" j% [* W
  24.     mysqli_select_db( $conn, 'temp' );
    5 i. i1 h4 |- b2 P# \

  25. ! x3 g7 y2 [+ ?3 K7 O0 I
  26.     # php中的文件锁
    ( Z; G5 b! n: {
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    * [+ b$ P5 s5 g
  28.     flock($fp, LOCK_EX);// 排他锁 * W9 d8 y% e' I" s
  29. 8 D: h  {2 Z! u+ V/ E  Y
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 5 m% [6 Q# C# C2 v- _! Q
  31.     while($row = mysqli_fetch_assoc($retval))# |" c3 k1 @8 ]; f" N/ \
  32.     {
    * ^2 G% P6 y0 A" R8 V
  33.         $id =  $row['id'];2 `$ f: G( Q6 Y
  34.     }
    7 l4 C' }8 G: ]9 G5 S! c% h& s
  35.     ' d- g: ?6 g! B4 g; `
  36.     if($id > 0)
    : p' W# [5 s/ o7 w- `) ^) P
  37.     {
    / e* N6 h% {) R
  38.         --$id; & |0 E$ N7 o$ k4 f
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); ; `5 N* N5 @) ^) \9 b8 w
  40.     }
    3 V) p! C% N* K/ |9 ?4 m, o, M
  41.     # php的文件锁,释放锁 % M' B( h% c+ D; l5 w
  42.     flock($fp, LOCK_UN); 1 p" Y* Z: U& M3 B
  43.     fclose($fp);7 x  l% N  i% u- r% Z8 W
  44. ! I% I9 K% G$ a  P* y  d# _
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');$ u. h4 A' @% s: ]3 X5 A+ `, f
  46.     // while($row = mysqli_fetch_assoc($res))4 `3 {% s& C' m) C" n6 e
  47.     // {
    / Y/ m/ i5 J$ g  ~8 X' f
  48.     //     $id = $row['id'];+ @  c( ^+ I& H5 r  ]; m
  49.     // }
    1 M4 R' O8 y  I9 Q6 d
  50.     // echo $id;
复制代码
& d' p0 r. `% |4 P8 Y- s8 M

1 z( k( V8 q: L; V2 b7 I1 Y+ a2 {& {
抢券活动实例:
  1. public function envelopeSnatching(){
    + O. _9 F  M* K& Z, G% C" a4 |
  2.         $lingqu = $_POST['type'];
    . r5 Y" i/ \5 d; Y* b
  3.         $uid=session('u_id');//用户id
    9 A+ V" L7 Y( l6 b8 C
  4.         if(!$uid){7 ~* p$ `) T; ~1 W! s
  5.             $data['msg']='您没登录,请先登录!';1 r0 [% m. R) Y2 j) X' {  L/ \( [
  6.         }else if(date('Y-m-d') != '2017-12-12'){+ o/ h0 e+ z7 o( Z% x
  7.             $data['msg']='不在活动时间内!';
    + j) I# |$ y( W1 g2 B. z) r$ v
  8.         }else{' k8 \, o4 u- o  X' {7 {* ]! Q2 E
  9.             $hours=date('H');//当前小时数
    2 O* V1 I4 y/ I9 Z6 X, A" O' Z
  10.             if($hours > '09' || $hours > '17'){/ u4 I, ]9 x- F: e
  11. $ s; c1 X8 H$ L1 Y: \
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的8 r3 ]8 ~# P5 P8 A2 [) `
  13.                     if($lingqu == 1){
    0 ~* K2 f7 C! p2 ?
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    + Q% y; A+ B, Y$ a9 c" E# X' `
  15.                         if($hours > '09'){
    ( G7 L, D" N$ D) K. ~- @, H
  16.                             $num=mt_rand(25,28);//优惠券金额
    : b: S1 t1 d3 G6 |8 D# ^8 {0 M
  17.                             $id=1;
    * ]9 A, E9 \3 l+ N! g
  18.                         }- [, f  e2 S" A/ `5 F/ r0 C
  19.                     }else if($lingqu == 2){+ a- x0 o  n$ B5 o& o
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    / i% m7 s1 W7 p8 U2 k& o, ^
  21.                         if($hours > '17'){
    ' _3 d/ |) }3 i  \4 [
  22.                             $num=mt_rand(50,55);//优惠券金额
    ! X( U6 x/ |+ S( n7 G
  23.                             $id=2;, g+ g  o3 Q& s. b
  24.                         }: h# h- a' h# o  S. r) y7 n6 \
  25.                     }
    1 v! D5 C1 h0 @6 L7 R# U2 a
  26.                     if(!$id){9 Y4 M# \3 K2 L+ C$ O- Z" P
  27.                         $data['msg']='时间还没到,晚点再来吧。';9 _5 \; m7 p9 Q8 y( ]4 G  `
  28.                     }else{5 w) n  I% q& C# s  S8 l& n
  29.                         if($is_lingqu){* ?/ d, T: E- Q2 ~- m3 {
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';; ~% J+ m/ `3 G! ^
  31.                         }else{: y$ E- I. J& ?3 W# O
  32.                             //锁表! U+ P8 B) g& Y! A7 A& g( ~
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    & |% A+ O4 P! @) c5 n$ y% s6 S
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();  V" J' {7 q  {% ?/ S
  35.                             if($active > 0){
    * l* U+ N8 z; ~6 \- R  C. s3 @+ ~- L
  36.                                 //开启事务
    0 w% t% ]6 v! j2 P+ }3 K- }
  37.                                 M()->execute('start transaction');
    9 M& X* h( L& m8 V3 a
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));8 T3 x2 \2 @. E! B0 V& t) ^, _8 c
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    1 `$ c) }# g) `" ?
  40.                                 $members_preferential    =    M('members_preferential');2 R2 I) c- @) Q" |2 H* k9 m# a8 U
  41.                                 //对应投资金额," P, _2 |0 |. ?' ^  w, i; }
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    9 N$ {( p0 y( {7 }1 T9 ^! @& B% u
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');+ P  q! o9 |3 c) b
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    1 q9 ~0 u( C; ]* l9 ?% c( Z0 |
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券9 H1 [3 S9 Q5 v3 Z, c9 Y8 @
  46.                                 if($save && $add && $add2){( \2 D" t$ t) S$ x
  47.                                     //事务提交" H& S+ B' Z) r/ w& c
  48.                                     M()->execute('commit');( [3 H. Z4 m) C0 x% }
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';/ C8 o! f7 D* S0 f# B
  50.                                 }else{
    7 p: \& P- V8 @& ~
  51.                                     //回滚2 R$ K0 G: L' u
  52.                                     M()->execute('rollback');. V5 m4 h! h; X
  53.                                     $data['msg']='未知错误!';- l# B) j9 X/ o& @; F
  54.                                 }
    - t" O: p; K3 @2 a/ t
  55.                             }else{
    : g: p. G. D+ l9 W
  56.                                 $data['msg']='红包已领完,你来晚了!';7 j& \& @  D2 e2 s# G, [
  57.                             }
    5 y: @1 P: b$ e, g: h0 t. F
  58.                             M()->execute('UNLOCK TABLES');
      u* _+ s* V# {$ D9 Y
  59.                         }! B, v; ^" F/ G& b% a0 a9 F
  60.                     }
    4 e! ^1 X5 Z. Y3 E& }" O
  61.                 }else{; v0 p7 l  [3 V9 w) `) E8 `
  62.                     $data['msg']='非法操作!';
    . n- x- r7 Y& _0 |: P6 q
  63.                 }
    ( ~: r' S1 u/ X& x- `9 d5 n
  64.             }else{
    7 _# K8 A$ X/ |' F* g) D
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    # N, H, I7 E7 a
  66.             }
    1 V! @6 k0 F0 L  e. b
  67.         }" o! n+ r6 e. E2 i; _2 X5 I0 E
  68.         exit(json_encode($data));$ O! ?$ g; \; F2 z8 J
  69.     }
复制代码
' |/ a) I4 T( g; W+ b
3 e9 y% @1 {% v; F' Z. z6 x
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 18:11 , Processed in 0.058946 second(s), 20 queries .

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