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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

, `9 d, A& f. ^
Mysql中的锁语法:
3 G. ^5 r. ^$ |  b* H6 XLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】& D/ y6 O. d' @, p
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表' K3 p1 F& y. N" [. u1 c; U
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
+ S$ N! e5 Z; N  C( {注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
+ g+ k  \# ?6 V$ U6 ^文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。2 `+ n9 U  H% k1 G( W1 n
测试时,有个文件就行,叫什么名无所谓
总结:: X2 U% P( u$ J6 ~. s
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:$ A9 o% \: L9 G" k
1. 高并发下单时,减库存量时要加锁
, V6 \! u7 C9 J8 R4 F8 ~2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    7 R: P7 M+ {* u* O
  2.     模拟秒杀活动-- 商品100件8 y0 x! @* |& h1 y; Y
  3.     CREATE TABLE ta1 [' P. B* F0 b' d" u
  4.     (9 w# N6 j3 K( p( C9 |0 ^
  5.         id int comment '模拟100件活动商品的数量'- v1 {% J: O4 o# C
  6.     );
    $ k& H7 T6 O5 h
  7.     INSERT INTO ta VALUES(100);* N' T9 l0 v3 E, @& `
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件4 {" a4 ?, L, u/ O
  9.      */
    # q% z9 O* F+ M- @$ `
  10.     1 Q$ a9 ?# T- q: B$ j
  11.     // 关闭错误报告) r8 ?2 y/ s3 V
  12.      error_reporting(0); ! `# J0 L: w4 b6 W6 o
  13. 0 g) u+ f9 V& r
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    5 J  a) n9 F( s' p8 K+ W, K
  15.     $dbuser = 'root';            // mysql用户名/ j3 {# \9 [8 k/ h
  16.     $dbpass = 'root';          // mysql用户名密码/ ~8 D1 K/ T! {/ R# h9 {- E' K5 k2 O
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);0 [- F% w9 [; j4 y4 o3 z
  18.     if(! $conn )% |: e( K1 e. g  x3 L
  19.     {
    ! j; K. X: ^8 ]: }4 t2 r9 N) f
  20.         die('连接失败: ' . mysqli_error($conn));
    / X+ o( C) j. L4 \+ q1 {
  21.     }0 g. {. b; f; s. h1 A4 [
  22.     // 设置编码,防止中文乱码; A4 [3 ~& G0 C5 F6 J. x
  23.     mysqli_query($conn , "set names utf8");% v7 I; o1 _5 t2 R
  24.     mysqli_select_db( $conn, 'temp' );
    2 o$ `$ L' N  L2 I+ Z, y! G3 J2 V2 A

  25. ) U/ X% r7 `, U
  26.     # mysql 锁
    ' u( c2 c8 O8 H  ?) C1 y
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    * K& p. `# J4 M
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 0 [" R- ~' |: N; f9 Z. ]
  29.     $id = mysqli_result($rs, 0, 0); 6 f; U& G  o" H; V
  30.     if($id > 0)
    5 m- W! |4 l( h
  31.     {
    : v# {( i% @% p# H; E) J
  32.         --$id; 9 D8 g4 w6 G. B6 ?$ F* J3 W
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    4 ?2 w. ]7 n" C" t) F# H8 c4 W0 N
  34.     } 5 B- _) |5 r# r! J3 D* q* G
  35. 7 U! _& |% f% \9 D3 n$ B  ^
  36.     # mysql 解锁 ) N" y% x9 P" s5 g" o
  37.     mysqli_query($conn , 'UNLOCK TABLES');8 {& X$ v9 s. c& T' c- x
  38.     //查询解锁后的id值
    3 X0 u( V! C5 C5 P4 D( h+ H$ U! |
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    + i9 q2 [, c# s9 t* |3 T
  40.     // while($row = mysqli_fetch_assoc($res))
    / L! H  `3 u! c( _  ~
  41.     // {
    " ?' p: t/ {: b6 u, l/ S) I- R
  42.     //     $id = $row['id'];
    8 Y! H+ _0 Z+ v! B4 `0 F
  43.     // }7 p/ M4 u9 g9 l
  44.     // echo $id;
复制代码

1 d2 z3 j1 N. m; X* U, A. K( W) i% \3 u, X  k
- }4 y* _7 [) G5 E( t' I4 E
PHP文件锁示例:
  1. /*! x- `2 h! L5 x0 A0 p
  2.     模拟秒杀活动-- 商品100件
    % F2 ~1 |7 O. o) s) i
  3.     CREATE TABLE ta0 I1 ~, _! V! M. R1 Q; j
  4.     ($ R/ n9 N, ?: C4 m
  5.         id int comment '模拟100件活动商品的数量'
    * _& T1 E: Y! `( W
  6.     );8 ^" O6 t; E6 {0 w. W% o5 k
  7.     INSERT INTO ta VALUES(100);
    3 V; r( o/ W7 O
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件% I/ y6 v6 c% N+ m0 a
  9.      */ 1 f" l* J9 P# }2 u3 w
  10.     ' }! j2 ^+ r# z: D, ]
  11.     // 关闭错误报告
    * v' k" e# b2 |9 S9 D& n" ^0 y3 \
  12.      error_reporting(0);
      i2 D/ n5 K1 y  \& |, b
  13. : Z5 x6 L% H/ h* h; l# Y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
      k' w% S; v( G4 p  o1 n9 S" R& V' K  h
  15.     $dbuser = 'root';            // mysql用户名. K2 Z- N% n) G$ Q( v3 q5 {
  16.     $dbpass = 'root';          // mysql用户名密码
    7 N$ h$ [; W* C+ l0 m9 U& O
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    % N7 B+ ^. `6 j8 X2 [5 r. d
  18.     if(! $conn )
    . r+ J6 b! j4 Y; V
  19.     {/ ]& P0 M; C$ `  o: @& J
  20.         die('连接失败: ' . mysqli_error($conn));
    ) D  n* ~( n. R+ L* w2 L+ x' i
  21.     }1 l& _7 \; i: [/ N4 R
  22.     // 设置编码,防止中文乱码2 a9 u8 E1 }8 c6 H. k
  23.     mysqli_query($conn , "set names utf8");( H/ ^( e  e9 v
  24.     mysqli_select_db( $conn, 'temp' );
    4 S* n* R% ]. s) L) G2 h4 L3 `

  25. + \3 _7 b+ Q7 Q! z
  26.     # php中的文件锁
    8 u7 O: T3 T' N; t$ ]1 o$ t- ~; u) H
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 + O% p) i( z+ E% w/ X
  28.     flock($fp, LOCK_EX);// 排他锁 ) t/ w* t4 [: ^0 r

  29. 9 x5 o3 D5 o/ Y% e: N
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 8 \/ A% x( H+ q7 @; c
  31.     while($row = mysqli_fetch_assoc($retval))
    . v8 _( ]# m! }9 x
  32.     {
    6 t5 n& U. D# U/ T2 I* \
  33.         $id =  $row['id'];# a3 q5 y2 `; u4 {/ B; V8 w( Q2 y
  34.     }5 O# k1 R! w; e$ z  u( D
  35.     5 b# G, G3 y; i( I5 ?6 u6 _4 A
  36.     if($id > 0) . e( k! x/ m' v9 G* i* X" f
  37.     {
    * s6 D+ V! `" N  N  e$ T% I0 `7 n% _
  38.         --$id;
    ) s/ J1 K1 O5 S9 `# e* x" }
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    % Z" U/ ~6 c6 |1 N
  40.     } $ G) l  _- d2 A: L- n% @- d
  41.     # php的文件锁,释放锁
    ' a) h0 v% V" p! K/ b
  42.     flock($fp, LOCK_UN);
    0 O/ z) o4 ~$ G& n
  43.     fclose($fp);4 w' F  A  ?0 S4 m* p* o

  44. 8 P* c7 p$ ?' c2 y7 X7 Q# B5 K& X
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    . x* x  e# d4 I" A, J& A4 v
  46.     // while($row = mysqli_fetch_assoc($res))4 q; t2 |- I  r; D/ t% R
  47.     // {
    2 w0 d% i2 c: T: M
  48.     //     $id = $row['id'];7 j  g0 I0 s; F, X
  49.     // }1 n9 [5 w7 I6 i# W  i( g
  50.     // echo $id;
复制代码

; x/ c6 \8 n, i. t" E
9 s4 L" m% [8 [
抢券活动实例:
  1. public function envelopeSnatching(){, @/ e6 I( w, b  K' X
  2.         $lingqu = $_POST['type'];( [8 @, l# ]; r- q. H
  3.         $uid=session('u_id');//用户id
    ; R1 ~6 y$ B  \/ V* P
  4.         if(!$uid){- a# T# a# h' |( y4 X. q
  5.             $data['msg']='您没登录,请先登录!';, {3 S( U. {, `( D; u
  6.         }else if(date('Y-m-d') != '2017-12-12'){; s3 l. |6 B* W2 y. U& i
  7.             $data['msg']='不在活动时间内!';
    " o' _0 H. m, m) V
  8.         }else{
    6 i1 F% _! N4 X) x% {
  9.             $hours=date('H');//当前小时数6 D" y, W, @7 M' a2 l  ?
  10.             if($hours > '09' || $hours > '17'){
    6 _  V5 p( E9 e+ I; y, {
  11. 9 M; f: u: D2 a2 A6 I
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的3 G$ J* U& D/ b& [; F
  13.                     if($lingqu == 1){
    $ p% P7 k  ~" [! }/ j5 {' b# K
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过" N' H* j1 ^1 N7 Z& g( T# S% D
  15.                         if($hours > '09'){/ _$ o* p7 }* C! f
  16.                             $num=mt_rand(25,28);//优惠券金额' }2 y$ ~9 I' U) I6 w& P6 j4 Y# M
  17.                             $id=1;* n6 N- w! O, H0 C! ~. _
  18.                         }
    & O3 V. Y8 [2 P! a
  19.                     }else if($lingqu == 2){$ }) G1 k/ z: M. h" i
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();1 D, `* d/ w. B9 ]1 p0 \  w( @
  21.                         if($hours > '17'){: ~8 @: M2 V- u2 ~9 \
  22.                             $num=mt_rand(50,55);//优惠券金额) f/ {% r8 v" [5 _; g% Z- B
  23.                             $id=2;2 p4 |+ [( [" H' C2 ?/ t' `7 }0 X( Y
  24.                         }0 S. R% }  W# \+ m' `; t
  25.                     }' y* X3 g7 [2 O
  26.                     if(!$id){; A. F  w0 G- ~4 X0 J) [) R" J
  27.                         $data['msg']='时间还没到,晚点再来吧。';* K8 T0 Z; ?. W7 q) @
  28.                     }else{7 d5 E/ M4 N' G0 ]2 ]7 U
  29.                         if($is_lingqu){& P+ J; V5 r+ Z# j$ h2 a" K
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    6 F5 B, J( x; D2 P" O
  31.                         }else{
    4 O6 a9 u3 K' b* c( E: x+ M# N' K$ h
  32.                             //锁表
    ) H- _$ x6 R# e; P* j( r. R
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');: @- J; L& o7 g$ h/ f8 ~* _3 }
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    : l3 s+ b( j6 ?% _) |' L$ P
  35.                             if($active > 0){
    # l* |8 d) @+ d7 y( ?8 M
  36.                                 //开启事务
    0 o$ z. b0 x) b7 ]
  37.                                 M()->execute('start transaction');
      \# d6 Q; k9 M! }- c
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    9 \4 x+ |; d% M% V  t' C# m
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    2 B( v9 S# H% J: r
  40.                                 $members_preferential    =    M('members_preferential');
    7 A. G% x- z  q$ i: I
  41.                                 //对应投资金额,
    6 H. P2 m& d6 P) ^! Q
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));) W$ ]2 B* l: Y6 h
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');  a$ l' {/ j& s: g- m' w" i
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    8 z" ^8 ^+ V  [
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券3 `) G5 P' `5 f4 q4 N* Z
  46.                                 if($save && $add && $add2){
    4 g8 o5 X( D" W( E6 s' T8 L
  47.                                     //事务提交
      Z; E# f8 Q0 s. ?5 c7 d+ M& r/ O
  48.                                     M()->execute('commit');& D- c4 ]! u# @5 k% R& P& |, E1 r% U
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    5 C/ C7 S6 E5 ?
  50.                                 }else{2 m# T' O8 R9 x. _8 l& r% k/ _
  51.                                     //回滚% G3 k7 ]& V9 f
  52.                                     M()->execute('rollback');: q0 K/ Y& P% S4 K% i2 P( b- _
  53.                                     $data['msg']='未知错误!';
    & C( w1 ~! W9 j
  54.                                 }
    6 ^& I2 O! l. _. O  {, l
  55.                             }else{
    " H* o: q5 l1 ?6 z( O2 y6 n7 z
  56.                                 $data['msg']='红包已领完,你来晚了!';3 M6 A7 M5 j. @  }
  57.                             }
      M2 ?% r0 @  R7 z: n
  58.                             M()->execute('UNLOCK TABLES');5 b0 `. n. D, Q* I
  59.                         }. c) |1 s% `3 N* y- S/ j9 N
  60.                     }
      s: e& H  W0 E/ E) `) v
  61.                 }else{
    2 {- r& s& ?3 _  B/ U7 M
  62.                     $data['msg']='非法操作!';
    * z& b) o+ `2 l3 _$ v! v
  63.                 }
    3 _: ]9 l5 c& A5 O+ k- f2 r
  64.             }else{" e- Y% v" y9 n$ M0 g
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ! `; ^6 L  A1 T" A' n4 B+ O
  66.             }' ^7 m4 I$ x7 m( I
  67.         }2 Z. u8 _3 n8 O/ ^
  68.         exit(json_encode($data));; W% U" \5 P, i$ V0 ]+ n
  69.     }
复制代码
* J4 V/ D8 L1 v; ~* c# {! R' i/ m6 Z

' ^- ~5 z" z7 G# d" ~, H3 ^
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:04 , Processed in 0.049966 second(s), 19 queries .

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