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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8212|回复: 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://请求的脚本
复制代码
4 S  V4 a# C5 A( q7 z/ H" E
Mysql中的锁语法:8 n0 u( @8 e! B( Y9 {
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】+ o4 I& q% j8 d
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
5 `" U$ Z, _5 _. M6 ^! VWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞4 D* P; {' Y2 B! n2 t! O
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :: B! X: l4 G8 G2 g. [
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
8 ~. h# `' d% s1 S测试时,有个文件就行,叫什么名无所谓
总结:( x$ q7 ~$ r! o8 c/ ]
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
5 d8 L" z/ t, U+ R1. 高并发下单时,减库存量时要加锁/ v6 t& \9 d! e+ o/ r
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*  S. ~+ G% v' ~
  2.     模拟秒杀活动-- 商品100件2 u  [1 D/ e3 B5 ~( r
  3.     CREATE TABLE ta
    6 K3 z+ i4 k# {  M* G2 f
  4.     (
    $ G" K5 T" Y5 A" _
  5.         id int comment '模拟100件活动商品的数量'
    ( m2 o2 \9 L" H! L: ?; v
  6.     );4 K7 c( H8 ?" ^8 o' @
  7.     INSERT INTO ta VALUES(100);
    , {7 d( c! o% X. F' h
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件) i0 y/ o* e/ z) z! J7 ?0 R! }
  9.      */
    + T- v8 f9 ]" v, Z! k7 D
  10.     $ J5 k8 e; J$ s+ C; m
  11.     // 关闭错误报告4 X( [0 w9 K4 u7 C
  12.      error_reporting(0);
    5 F8 O' S0 o, m! f2 s  _: i

  13. # f2 h* ~! u& [7 F6 c/ G
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址- ?7 X& |/ G: B. I" O8 u
  15.     $dbuser = 'root';            // mysql用户名% L9 l/ q7 E8 R% y
  16.     $dbpass = 'root';          // mysql用户名密码/ u6 g9 T" k- y
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ' t7 T' g$ k, b/ r0 d
  18.     if(! $conn )  y/ Y, g. M0 Q& Z9 b1 d! U; o  a; i6 Z
  19.     {6 f1 p* ^8 y0 g+ w4 X% W/ L: P
  20.         die('连接失败: ' . mysqli_error($conn));1 j2 V, B- r, b0 w: p. @. Q/ r4 f
  21.     }
    7 Z# _7 K1 A' |" _, p. a
  22.     // 设置编码,防止中文乱码
    % o* n  f2 w: `$ t- `
  23.     mysqli_query($conn , "set names utf8");
    . r2 m- d' J4 a5 K" z  ~$ W! H
  24.     mysqli_select_db( $conn, 'temp' ); & o+ p, B3 L* C! k" y% E) m: v

  25. 5 S2 x' u4 H3 Z" d, K5 v1 X, I
  26.     # mysql 锁
    % D3 E  I6 Q$ g7 F5 a
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 1 T( d7 a7 p" U) Y' M& o4 R: j
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    ) z' ]$ @. j/ D
  29.     $id = mysqli_result($rs, 0, 0);
    & E& U2 O2 Y* V2 c9 u" c% U
  30.     if($id > 0)
    % z4 h; Y% Y1 q& z/ Z9 Q
  31.     {
    9 a9 V  X5 V) p- R
  32.         --$id; : h2 f' f# h" y0 `! \5 j' q
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); / @& ^1 }. ?2 c" S4 ~& ?, P
  34.     }
    4 X8 U" X& p. Z4 z0 I4 O6 s4 P6 c* e
  35. 1 C4 Z: T2 }& Z/ K+ S3 F/ q4 v
  36.     # mysql 解锁 % }$ X( y& Z+ {$ y1 Q
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    8 Y4 r, K* R+ F6 e! ]
  38.     //查询解锁后的id值- ^5 D* a. l$ x  h' r, d+ |7 ^
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');/ `' d# H% C. w4 N1 b" l+ [
  40.     // while($row = mysqli_fetch_assoc($res))( j  R% f/ D3 ]0 `
  41.     // {
    ' ^7 _- u& z% l8 }1 W, `
  42.     //     $id = $row['id'];, I) q  o1 Y" ~  I6 ^
  43.     // }
    ! |# Z; Z, c) K3 U3 F& X
  44.     // echo $id;
复制代码

" r' F5 }2 D8 N  c
* o% ~! h+ X, x9 G9 O
) p( t( w' |* Q( v( \  y& Y
PHP文件锁示例:
  1. /*
    ( x" ^$ A5 Z' m5 _1 w9 N+ k! \7 t
  2.     模拟秒杀活动-- 商品100件* |3 b2 K( R0 w: n0 y& H' Q
  3.     CREATE TABLE ta" M- Q0 @+ _. c6 z$ v0 N8 |, M
  4.     (2 ~3 m/ Q5 ]; E6 e2 c; V8 p: e
  5.         id int comment '模拟100件活动商品的数量'8 O1 x: t! ~$ E' }
  6.     );
      |9 e2 t0 i( m, ?
  7.     INSERT INTO ta VALUES(100);
    8 ~! @% @+ U/ f2 Z0 U+ ?2 p
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件+ q7 m3 f8 `, X4 w
  9.      */ * X' J) O: u, a
  10.     2 U+ V7 {& }; @  w* j& P( Q
  11.     // 关闭错误报告: N2 e2 k/ z+ E
  12.      error_reporting(0);
    8 c+ ^  h. w6 z" D2 ~0 ?! l
  13. # W$ t# J2 O# Q( k
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    . h, ^) M9 _7 p, D; [
  15.     $dbuser = 'root';            // mysql用户名
    - B. ?- l3 o$ Z' F# G
  16.     $dbpass = 'root';          // mysql用户名密码
    0 w# P/ t0 M/ D$ n# m7 F
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    3 p: z3 h) N, ~8 [2 Z
  18.     if(! $conn )! T8 c$ W) p5 K- m. G& C# a0 d
  19.     {1 Q. ^7 H1 r' r, a* R
  20.         die('连接失败: ' . mysqli_error($conn));2 p* C$ l' O" X7 z( }
  21.     }
    " i4 |8 Y: m/ C: h& o- c
  22.     // 设置编码,防止中文乱码6 R; j6 c7 w! T: b9 O0 g0 n9 ]
  23.     mysqli_query($conn , "set names utf8");) d  S( k! Y+ h2 Z8 j0 [
  24.     mysqli_select_db( $conn, 'temp' );
    5 T! K) ]8 k4 W+ U& m) q

  25. ! p0 e" e: Y( Y) {
  26.     # php中的文件锁 # O& o# y' P+ H* ]& R
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 * F3 ~( c( p, P* m+ }- Z
  28.     flock($fp, LOCK_EX);// 排他锁
    : s& X+ N& H! X

  29. 5 @" v9 d  k, B& R
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); & h( i9 s1 H/ }' K% u( k) l  U0 V5 g
  31.     while($row = mysqli_fetch_assoc($retval))) D( D) G. F4 [- a" Z
  32.     {
    ) V, H  ]9 x- v8 S6 ^9 j2 P- s
  33.         $id =  $row['id'];! j$ f9 n' r6 Y2 I2 J. ~- y
  34.     }
    ' z) @. ?$ n& [
  35.    
    9 \" S# P7 T2 o  S+ j3 j2 A5 W
  36.     if($id > 0) % \% u3 u# {8 w/ S3 R" i' G
  37.     {
    6 d7 N* n$ x' L6 _
  38.         --$id; ! _+ K. ]* K( E+ D2 G# r, r: g5 ~
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    $ y4 R* P- N3 T
  40.     }
    ) i0 B' r/ V- V; m
  41.     # php的文件锁,释放锁
    0 ^* J" C' e' Y8 q, G+ @, H/ D' K
  42.     flock($fp, LOCK_UN);
    ; q8 j+ T& q0 `( `  k) L7 _8 h
  43.     fclose($fp);- F" S6 F4 I8 l. o

  44. ! E* r$ [6 E- E% }6 V' w# l5 x1 G
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ! H" r) R4 ?8 B- v
  46.     // while($row = mysqli_fetch_assoc($res))
    # V1 _! A* k- K5 _
  47.     // {
    5 U& ~: u& O  L7 E
  48.     //     $id = $row['id'];+ s: s) I4 U6 T& [6 u+ v
  49.     // }
    . M- h4 I) p4 O
  50.     // echo $id;
复制代码
+ Z9 t& q' v/ g0 M, Q+ l$ W
9 _* I5 L: x) K3 `9 O
抢券活动实例:
  1. public function envelopeSnatching(){
    + F# D( F9 ~! @0 u# q$ t
  2.         $lingqu = $_POST['type'];
    % l& i3 K+ Q" T' l6 X
  3.         $uid=session('u_id');//用户id# f# R% p4 I+ ]8 u; ?! B3 o* b
  4.         if(!$uid){) i, y9 Z* j& r4 g/ ^2 `$ K
  5.             $data['msg']='您没登录,请先登录!';
    : @( O1 m- X  i6 T) o! [
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    * Y% b; P5 A0 h# T, J  c/ a
  7.             $data['msg']='不在活动时间内!';
    - ^+ r7 t& x5 v$ O; D
  8.         }else{
    2 L7 j1 ]4 U" f  d1 d, U  j
  9.             $hours=date('H');//当前小时数  W% H: v3 @2 t8 y
  10.             if($hours > '09' || $hours > '17'){
    % W8 V( m2 g: |8 [

  11. , R, \5 o! g5 i9 A
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    ! r' l& P' Z3 k- m1 m1 c9 r9 L
  13.                     if($lingqu == 1){
    3 |3 X$ `  h/ w& D8 [
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    0 ]7 O2 v& g$ z: K1 d* `7 w  O+ J
  15.                         if($hours > '09'){
    " R8 }5 ?" }1 |2 `: D
  16.                             $num=mt_rand(25,28);//优惠券金额& h1 `8 n" T+ K0 e
  17.                             $id=1;& Y) d: S* N/ ~" R0 q2 q( v
  18.                         }* H4 V/ q+ \- b5 z2 h
  19.                     }else if($lingqu == 2){  [' f8 r. n& J7 U
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();& T5 [$ E* U+ J. i
  21.                         if($hours > '17'){
    ! Q+ }, o. g3 }5 E, `: t1 T: I
  22.                             $num=mt_rand(50,55);//优惠券金额
    # s: ^# C' Z, S. \& o) ^( a. x
  23.                             $id=2;
    ; s8 g# v2 z9 k9 s; b+ K
  24.                         }9 N. Q5 {4 o$ ^  S" J. }9 }
  25.                     }9 S/ C8 R/ E7 B0 K% F6 Y, m
  26.                     if(!$id){) x3 G! k8 a$ i! F$ E3 r& q) `
  27.                         $data['msg']='时间还没到,晚点再来吧。';3 g% T: d% `7 x
  28.                     }else{% N$ Q' v/ ?4 s# M1 M1 C6 n
  29.                         if($is_lingqu){9 t& p6 @$ [6 e
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    5 {2 {# {) A3 P( T! V+ M
  31.                         }else{, m  v* t* c2 C2 O( \
  32.                             //锁表
    # E# ?2 V: F( X6 c
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    1 N8 r$ O' U, X, Z4 _2 |  P
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    4 ~, ]: _8 {8 u& p! n
  35.                             if($active > 0){
    / t; ^" i. |4 q
  36.                                 //开启事务
    6 x. g% S! B/ P7 ?
  37.                                 M()->execute('start transaction');
    9 }) O) b. [  M2 `$ w
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));1 e! D# v+ ^, t. M8 E; A6 s
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));7 q$ t; I. ~/ A( e6 n
  40.                                 $members_preferential    =    M('members_preferential');9 j0 `) [! g$ e/ G, f0 n
  41.                                 //对应投资金额,
    + m" j6 j+ r7 S3 p$ S
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));5 M  x' h8 @+ C5 h( Q. V9 g. M
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    , a1 S# l: R$ G) S' U& ?* Z  o/ `
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间6 [/ n3 ?/ H" |# K9 R0 g1 Q
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券1 i3 T* a& C; g
  46.                                 if($save && $add && $add2){% j5 q9 e  [* |( G( e
  47.                                     //事务提交
    ; f( ^, Z: a7 Z3 v
  48.                                     M()->execute('commit');
    0 G6 Y& w" f7 ^6 x5 H+ E
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    $ O: F1 y6 [/ A8 L/ V* Q
  50.                                 }else{8 H; V) T! j/ u4 c
  51.                                     //回滚
    ! z& r+ B& F- k2 ]- e# N( e
  52.                                     M()->execute('rollback');
    ) \1 S7 P8 J4 S
  53.                                     $data['msg']='未知错误!';) {; m' ^" K7 X7 j  ?8 p6 B8 `4 E5 G9 _
  54.                                 }8 G1 D( ^. b- @4 H3 ]1 {7 @
  55.                             }else{) J2 _% O$ _% i
  56.                                 $data['msg']='红包已领完,你来晚了!';& a# I" p  R9 r) d; |: }; S& L
  57.                             }
      N. X$ a5 L6 B
  58.                             M()->execute('UNLOCK TABLES');3 f5 F+ H+ Y1 T# [
  59.                         }
    / n6 P9 l$ w  ^- z# a' ]% z
  60.                     }
    + W8 x! }8 t  ^/ q# R) i. _
  61.                 }else{
    6 ]" x% E( H, m2 e; }7 ?
  62.                     $data['msg']='非法操作!';$ o3 O0 @- Y2 k' i. n& {5 B2 V
  63.                 }
    6 D" m9 ~8 Y  I1 l. d# M
  64.             }else{. g8 ^" a4 C2 W
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';/ h" b9 z+ z2 K! y" x
  66.             }0 k# h8 j) A; v/ S* E. j9 F
  67.         }' U, R: c( F- ^& _; d4 N
  68.         exit(json_encode($data));
    1 s. d* F* Y: _% K" G  j# s) C
  69.     }
复制代码
, X3 R& Q) y) H: N1 K: b
& R8 {3 d4 {6 S) e8 i
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:44 , Processed in 0.054100 second(s), 20 queries .

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