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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3999|回复: 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://请求的脚本
复制代码
6 _. {5 D" N! u. E( F
Mysql中的锁语法:
; S$ E9 K' D/ B; q$ @9 T1 vLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
  r" i: b0 f9 TUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表2 Y3 E  Z. K. C4 I, U' }# W
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞: r9 B8 s" M- X5 ~3 _. x" O/ ]
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :% w" }; v. i  h
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。$ g. r2 V- F" N  `  D. h; k1 h) G+ U
测试时,有个文件就行,叫什么名无所谓
总结:
/ g; ^! Z, R% j# L4 B; O% K项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
% m5 l& \3 e. ~/ P; W! v* }( `1. 高并发下单时,减库存量时要加锁
; a+ [- e- B3 Y. `7 n4 M! k; k2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    $ F6 v0 p1 z* R' P% [0 s
  2.     模拟秒杀活动-- 商品100件& b% H8 H- `7 K3 P# {9 c/ x) @, `: `
  3.     CREATE TABLE ta0 W+ U9 r. N4 @6 f
  4.     (# B& r' ^7 n/ C: ?. w; |2 l. l# |* q
  5.         id int comment '模拟100件活动商品的数量'  n6 J9 u# {1 I0 [9 a2 m. I
  6.     );
    ; M- R' s! o; d
  7.     INSERT INTO ta VALUES(100);
    - x: Z. V$ Z$ j: r- K) {
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件1 L" t+ U$ K' G! S
  9.      */
    % _, n! ^  I' k
  10.     & f2 f3 C* Z( h) g( y1 [
  11.     // 关闭错误报告" t/ m. W5 H. n. k/ K4 \3 K
  12.      error_reporting(0); ' y- K! c: x$ B  P( x0 @
  13. 7 t! O# u6 [( Q: }/ y6 L4 E) N
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址) Q" o  k& h' Z1 k$ M4 }8 W
  15.     $dbuser = 'root';            // mysql用户名) b7 u  v! x1 c  h- _5 }+ \: \; D
  16.     $dbpass = 'root';          // mysql用户名密码
    % b* `5 x) M+ _- V: E9 O
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    , \% Y7 [' |% P& _; k7 H/ E
  18.     if(! $conn )
    & e; D# ?# N# D/ D: ?  d( d
  19.     {) d/ v% k: h9 e% ?  U9 H* T5 A
  20.         die('连接失败: ' . mysqli_error($conn));* q2 D  l* J4 I) ?0 i
  21.     }
    7 M) b) B+ y$ B2 o
  22.     // 设置编码,防止中文乱码
    0 z% J2 n3 S0 n0 F4 P+ \" H
  23.     mysqli_query($conn , "set names utf8");
    ; c* N' K0 o1 a% b
  24.     mysqli_select_db( $conn, 'temp' ); $ ]; ^1 d. e9 E, n
  25. " a' T$ T: u% j/ @
  26.     # mysql 锁
    / @, P  ?7 @# x$ w1 W4 B7 j
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    + Q" h( t. u2 o- n
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    " r. @  t0 R( D- K8 b0 I
  29.     $id = mysqli_result($rs, 0, 0);
    , s7 n2 O1 B7 \
  30.     if($id > 0) 6 g" t& T, x( p, u8 k% B  d3 b5 Z
  31.     { " Q2 s" }6 X* M/ ?' o: r
  32.         --$id;
    # ?7 U3 i# i- A" ?, m/ @0 i% u! u
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); / K9 H) v. }, P) M
  34.     }
    ; g- S* g* b! k+ J+ m1 b1 R
  35. % M+ K/ w, o9 z* i' V* |- e) g
  36.     # mysql 解锁 $ q1 ~- l  N, U6 b
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    8 k3 ]2 l( A) W. R6 G/ u" f
  38.     //查询解锁后的id值; T& s& ^6 h: M) |1 `! g  j
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');! L- ]  H# B" K( ?5 y' P; k* e
  40.     // while($row = mysqli_fetch_assoc($res))
    9 X/ t, Z. ?" p, i+ T" R2 y; u
  41.     // {
    ' J0 L( b3 x/ P) a% s0 @
  42.     //     $id = $row['id'];
    4 k6 h) }+ s$ m( Q0 J, P
  43.     // }" r4 m, l( G% G. P8 _
  44.     // echo $id;
复制代码

: F) ^% j& B; i& S2 T. o- A) {: f5 ]% M9 Z- k6 l

0 ^' N& w9 S# I- c5 {, n
PHP文件锁示例:
  1. /*
    5 M; M$ b* K! T3 U) d3 A: u
  2.     模拟秒杀活动-- 商品100件1 ~$ M) G6 C' W- G
  3.     CREATE TABLE ta
    9 K& W& D; z  t* r, r
  4.     (
    9 [: O. r% \! f' [% o+ I2 E
  5.         id int comment '模拟100件活动商品的数量'  C: e( w) }; V. n" b6 S1 Q
  6.     );
    ! F* b+ V& S3 b
  7.     INSERT INTO ta VALUES(100);
    ! e& ~8 p8 }$ I
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件# D6 Q. C, H9 R
  9.      */
    + K0 @8 Q+ p! W' {  S
  10.    
    - r; f$ v- w/ H' x$ X. `' T5 M# T
  11.     // 关闭错误报告
    & C2 o) @6 b9 Z6 m4 b* z
  12.      error_reporting(0); ' A* N) z& @- U  u+ [5 M
  13. , L- C+ F: D, w* I: {; Y! Y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    4 c6 G6 {5 \9 x# _
  15.     $dbuser = 'root';            // mysql用户名
    : u9 H0 ]2 ?" H3 p; a
  16.     $dbpass = 'root';          // mysql用户名密码8 P1 }, i- M& n0 g: M( f+ G" k
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);' @# U) \3 V2 L  v% W, ]/ {
  18.     if(! $conn )& B# w6 }% }$ B7 B' f$ Y
  19.     {' k- A# a+ u$ @$ [% s3 ]5 K4 p
  20.         die('连接失败: ' . mysqli_error($conn));/ n: g: o( [6 t& s
  21.     }
    . J2 ^: U: X* B) p& {6 W# |
  22.     // 设置编码,防止中文乱码3 W$ ^" k- r# y+ ?: r7 e& B5 K$ K. M
  23.     mysqli_query($conn , "set names utf8");
      P  c6 C0 S+ e" ^* C8 s& t4 p0 b
  24.     mysqli_select_db( $conn, 'temp' ); + S- o. A3 r& K* H: `' Z8 Y" c
  25. 6 R# o) B$ w" |( q. s) d% s/ q  C
  26.     # php中的文件锁
    3 n& g/ Y, p$ ^* n# y5 L
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    2 E( r% o- X& M" [, r/ y
  28.     flock($fp, LOCK_EX);// 排他锁
    3 M9 \, \" p7 P2 K/ W

  29. ; Q* }) d( h& g1 y
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    1 c  e$ F4 W- i5 y1 F. z
  31.     while($row = mysqli_fetch_assoc($retval))$ [( a  H2 K* @1 K1 b3 X2 m3 R
  32.     {
    ; _$ c/ L/ R, d% D, k+ d) d
  33.         $id =  $row['id'];
    / A* i: @4 P3 y
  34.     }+ O: l9 |1 q" U" r
  35.    
    6 x$ q- @; s+ J% m7 O* a
  36.     if($id > 0) ; h; G* U& Q0 Q* c, ~
  37.     {
    + L, h1 V  Y9 o% _( `8 U4 F& q5 d; G# h
  38.         --$id; ) D" D' i. V  |6 w5 l, f* A2 i6 B) T4 m
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); + [# ^$ C; T( p' E
  40.     } 3 i3 x0 ?+ o) S7 d, Q1 u
  41.     # php的文件锁,释放锁
    % D: a. ~3 Q" z6 u+ B, p
  42.     flock($fp, LOCK_UN);
    7 V% r+ o( M% K1 M/ {  T7 ?4 s; \, c
  43.     fclose($fp);5 N' W+ x& x$ S0 r( n
  44. - P4 C+ J5 H! T
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ( d: W/ s+ ^* ?9 ?% H
  46.     // while($row = mysqli_fetch_assoc($res))& o9 f, J$ u+ J
  47.     // {
    + s" A$ R8 i, G4 Q$ P; v
  48.     //     $id = $row['id'];
    7 H5 M/ S- t5 K+ D/ c$ l$ T8 }. E& _
  49.     // }
    # l* ]+ h% W) M0 I( M
  50.     // echo $id;
复制代码

9 p, S5 I( @, D9 m% w! \# ]# s) m- k4 Q; l$ f
抢券活动实例:
  1. public function envelopeSnatching(){
    8 h- M# G# X- o! x
  2.         $lingqu = $_POST['type'];
    % z0 y+ g1 Q/ h: R, v/ N( X
  3.         $uid=session('u_id');//用户id
    % C- L, e8 _& v5 r. J& O5 H
  4.         if(!$uid){
    & r2 N+ l8 n, t1 O" [: _4 H5 k
  5.             $data['msg']='您没登录,请先登录!';  b( \  X) ]  i  Y* ]8 J7 p
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    ! P6 ~7 Z% |! A8 G9 j
  7.             $data['msg']='不在活动时间内!';
    6 @1 t& {9 M& A# E  \, G
  8.         }else{. Q- \: D; I/ G' ]5 E
  9.             $hours=date('H');//当前小时数! r) {' _! q7 U- o
  10.             if($hours > '09' || $hours > '17'){' D4 O* a7 t8 Q, y, X
  11. 3 C. W* r3 ~0 n( ^
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的: e  ?1 g4 K4 d, Q: l
  13.                     if($lingqu == 1){) r* E% i9 a% o, O  a. |3 V
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    * h' r/ @1 r: j8 T/ @' H6 M3 d
  15.                         if($hours > '09'){6 {% Y& N3 {  c8 }- e0 h
  16.                             $num=mt_rand(25,28);//优惠券金额
      h  b5 J3 l3 [; A3 Y6 z6 a
  17.                             $id=1;
      e# E& w8 b. [4 ?# H" Y
  18.                         }
    # |9 Q8 s1 @) I2 g. ?& j
  19.                     }else if($lingqu == 2){
    / B, X, j1 L6 w, w8 b" P' Z3 l
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();: _9 i0 ~4 `6 L, T* _9 o- s
  21.                         if($hours > '17'){
    2 ^/ F( v$ _4 o" L) u; ^
  22.                             $num=mt_rand(50,55);//优惠券金额
    5 f0 f- ^( l4 D, G  @- m1 ^. w
  23.                             $id=2;+ U0 F1 W9 Q$ U' Z6 S! q3 `( b
  24.                         }' Z' M9 C  l8 \8 `7 P$ u: B' @
  25.                     }1 T$ |" C3 f+ |- {& F
  26.                     if(!$id){* J2 v, u; J6 Z+ ~/ a; q9 t/ c
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    8 ?( c# U: W0 ~8 E3 ], D: e: |, Y8 d: N
  28.                     }else{! l- P$ I+ j; h
  29.                         if($is_lingqu){
    + c/ F9 {) c7 r1 y; |
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    % g: v: b5 ~* Q$ L
  31.                         }else{1 ]& R$ p+ R3 P1 i5 L, h
  32.                             //锁表
    7 m" e0 O: ^! f. W7 ]- c3 t
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    7 x: z$ Q# F$ K; I; L: ~; v
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
      o" r/ [0 j/ J  C/ L
  35.                             if($active > 0){) S3 x) b/ h6 l, U6 c" [& k0 H! C
  36.                                 //开启事务
    : M6 t+ v4 n& O& p# G8 f* f
  37.                                 M()->execute('start transaction');
    * B; B- l/ _3 Z" c5 |& Z& u
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    ! l- Q7 J  J0 ^
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    5 \! }5 H* A! Z# f4 N$ q
  40.                                 $members_preferential    =    M('members_preferential');
    1 q$ Z3 U! e9 r- x
  41.                                 //对应投资金额,
    4 Z+ O9 \9 \. y& e) Z8 I6 d- h7 ^
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));$ t3 w6 j+ g6 i; W+ c* o8 L
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');- o6 r+ T* Q& J7 A: u8 @
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间: Y/ G0 M: `# B
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    0 ]: ]; s# @3 ~: Y' O
  46.                                 if($save && $add && $add2){
    ( _- {2 X9 l5 s* ^( J. w
  47.                                     //事务提交
    8 s, Q4 b) d3 t% o" Z- ?
  48.                                     M()->execute('commit');$ P' P- f& _: y" `% A: k" s  `
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';" E3 w3 B( x' Q  V0 p$ q
  50.                                 }else{
    $ J4 l1 c  Q0 W7 }' l
  51.                                     //回滚
    3 V. J# u% k" W& M9 b
  52.                                     M()->execute('rollback');5 r' S. s7 C7 n
  53.                                     $data['msg']='未知错误!';# ~. `: `# y: P* Z3 g$ C0 Z0 P
  54.                                 }
    ! l( Q4 t8 q0 G/ H* o  s
  55.                             }else{
    : W5 Y7 d. s0 @# m
  56.                                 $data['msg']='红包已领完,你来晚了!';4 L; M) h2 c9 W4 F: e# Y: r
  57.                             }
    ; z  t; c5 i" a8 j; B
  58.                             M()->execute('UNLOCK TABLES');% G4 I( P. f, x5 [- B
  59.                         }( ]6 f( W$ H0 e
  60.                     }
    0 L( w( i& r+ J
  61.                 }else{# H9 L- B1 h( J3 Q- H
  62.                     $data['msg']='非法操作!';
    * `6 n* K+ r! Z" k
  63.                 }
    0 }( D* z! @* p" A
  64.             }else{  b2 v2 o5 M9 `
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ) y; e* u0 {3 S+ g+ E- c
  66.             }2 }# T" o; i% g
  67.         }7 z8 S: Y1 @( {& t+ c) ~0 O
  68.         exit(json_encode($data));5 F1 ]3 `. _* v4 g2 K3 o; t
  69.     }
复制代码
# k) M- l* _, s3 Y3 M

4 T! r' x+ w# M7 p
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 17:22 , Processed in 0.111318 second(s), 19 queries .

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