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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9870|回复: 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://请求的脚本
复制代码
, o& [$ q9 J1 s6 X
Mysql中的锁语法:2 k, T3 j, w* T
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】0 \. ^1 t+ ^* v( B4 D# P8 h
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表- A* D! I* g/ I: K" X
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
) U5 r9 T& G4 f4 d注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :5 w) h9 U1 w0 H. E( A
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。( a! z4 B& k; t" W& A: P; _5 p
测试时,有个文件就行,叫什么名无所谓
总结:
1 g; w  {  j& D5 L; T0 h. H项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:8 `/ n4 i8 q+ T* d/ U2 s" y( I
1. 高并发下单时,减库存量时要加锁" R/ @: I- P/ V( I6 T
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*- ?6 Z$ Q9 [5 x9 j' r
  2.     模拟秒杀活动-- 商品100件
    ; [( }* q- n: _# \6 u, n
  3.     CREATE TABLE ta
    / H% S; {. O' d
  4.     (
    % K& S8 H2 [* P, d' M0 f1 t
  5.         id int comment '模拟100件活动商品的数量'' X5 V" c* q: V+ D0 A4 v) |- z: a: s
  6.     );! y, {6 m& I6 t# t; i: p
  7.     INSERT INTO ta VALUES(100);
    + g3 x0 C( O4 m4 g
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件; b# `7 N. Z; N2 D5 t' k
  9.      */
    . Q0 ?. P# _! b! [) M
  10.     ) @5 o, D3 ]/ T8 d' g" \5 U
  11.     // 关闭错误报告
    0 d  _9 F6 Z/ `. T4 T; E2 `& T3 P
  12.      error_reporting(0);
    : a) \2 F7 K4 ~) T" M; B

  13. 3 _" L  E7 |! B# b9 M  u4 j" q
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址9 g( z. }- z* O
  15.     $dbuser = 'root';            // mysql用户名
    5 @: a- o+ c9 s& U6 U
  16.     $dbpass = 'root';          // mysql用户名密码
    4 l+ O) Y; o( L0 Z( m+ ^5 g5 O
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    1 a  q1 k# A2 N% d) ?0 N
  18.     if(! $conn )( \  \+ Z/ {& Q' g3 K
  19.     {
    ! ^7 S' W! n+ G
  20.         die('连接失败: ' . mysqli_error($conn));
    7 |  h4 Q( _1 \6 l, I
  21.     }
    / Q+ v# N2 Z3 z2 [. E
  22.     // 设置编码,防止中文乱码
    " f* C8 B0 w8 [" k% I
  23.     mysqli_query($conn , "set names utf8");
    * \/ c) R! c! K. D; }3 m
  24.     mysqli_select_db( $conn, 'temp' ); , `$ _' k* C$ V4 Z- q9 q" a6 x+ k* P
  25. - l9 w) f% w% @# M, a; j0 u
  26.     # mysql 锁 8 s* @: ]6 |4 V8 h' N
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ) O. g) k0 z' u" b( ]6 B* P
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); & ^. i3 N" U1 B. p- r. q% l' S
  29.     $id = mysqli_result($rs, 0, 0);
    9 Q# j  _" r! E& b$ e
  30.     if($id > 0) / L% e7 L, A0 E, F0 h. _
  31.     { / J, E/ K  `( _, J% L, \
  32.         --$id;
    : }  n; }; R& `: Q9 _
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    5 P# q2 f  d+ N
  34.     }
    9 H5 l$ x6 g8 c

  35. . _' @) m, d0 r* I! v
  36.     # mysql 解锁
    1 v# `- b6 i7 ]8 E: l
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    # _6 @' H( U1 m5 |7 H
  38.     //查询解锁后的id值2 J% C$ h8 T. P- A) W7 n( V. V% @
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    : \7 C9 [: w1 G" o3 E, k8 q
  40.     // while($row = mysqli_fetch_assoc($res))0 s! ~$ j0 ~0 Q7 `+ P4 m. R
  41.     // {
    , ^9 o# E, ]: a1 m: r
  42.     //     $id = $row['id'];5 T. ^* I# A6 ~. X2 z6 z
  43.     // }
    9 P; R( Y9 I. F0 V' L. m
  44.     // echo $id;
复制代码
" K7 v0 T: R( d$ V' }
( J% L; ~( A) v' \$ M
0 h- z4 C! T! [. |: X+ p2 W
PHP文件锁示例:
  1. /*; D- w* f1 k. q- }9 E4 x1 m8 R% i0 y6 y
  2.     模拟秒杀活动-- 商品100件$ C& h/ D* G  c4 A" @9 N6 |
  3.     CREATE TABLE ta
    . i% j; h, u5 d  O
  4.     (2 J& `: T7 `7 L2 |0 F/ c. a
  5.         id int comment '模拟100件活动商品的数量'7 B- g- m( N+ H% j
  6.     );0 T. i1 f3 L. F- h5 Y1 U- M4 L( u
  7.     INSERT INTO ta VALUES(100);
    9 G6 T6 p: t' `! m: `
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    1 _& j* r% e7 D$ G: y$ ^  t/ i$ T9 a
  9.      */
      w7 z2 l  {) a. T; X8 i
  10.     - o  c, t# D4 o! W
  11.     // 关闭错误报告6 V( O" B# D  [& A, z
  12.      error_reporting(0);
    ' V5 H% d3 N% V$ c

  13. 3 t* N% q: b7 u8 s8 O
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址$ x; F* g. a  [1 r8 k
  15.     $dbuser = 'root';            // mysql用户名
    4 f3 S2 n; [9 P4 P
  16.     $dbpass = 'root';          // mysql用户名密码
    ( C* w# B1 o. v' g& Y9 p
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    " e, p0 s% j- o$ l; e( p
  18.     if(! $conn )
    * K& f+ ~/ Q5 Y1 s) C8 p
  19.     {: _, G( D+ l" l
  20.         die('连接失败: ' . mysqli_error($conn));  N2 B0 p6 J* U# f. T' h# M7 [7 W
  21.     }
    8 I% U# P3 B2 B( `$ m
  22.     // 设置编码,防止中文乱码
    " P1 {. d: q, t
  23.     mysqli_query($conn , "set names utf8");
    ! g; I! @+ C9 D, d: u
  24.     mysqli_select_db( $conn, 'temp' ); - A; Q. t( l- o/ Z
  25. $ m. f1 d/ F6 {0 C: j0 L
  26.     # php中的文件锁 5 K2 V! @/ a2 D2 _+ b4 |3 Z/ [
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    . b; w; d+ v% ]
  28.     flock($fp, LOCK_EX);// 排他锁 3 F( y0 {7 w( c- _

  29. # e: r$ e6 G. i
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); : ^2 F( {) X6 `$ w& \" F4 N
  31.     while($row = mysqli_fetch_assoc($retval))) G. z9 ?9 h' x3 M5 \$ x
  32.     {. E  H  r: d6 L
  33.         $id =  $row['id'];
    . o0 {  _% f! q8 e9 w
  34.     }( }& k0 P, E( y3 |
  35.     ( x; l0 N' N( s7 ]* L( [
  36.     if($id > 0)
    $ k  J+ P0 G% u! T7 m" _
  37.     { 5 ?! k9 f- B; \: ^
  38.         --$id; 7 _( k5 j7 n& [" R
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    " h/ d$ a" d6 r) G
  40.     } - r" X& P) B# O* k1 E+ S7 P* j6 m
  41.     # php的文件锁,释放锁
    . ~' p6 U1 l- c( I; ?. x
  42.     flock($fp, LOCK_UN); 4 }  c$ m7 R; Q) t8 N" U
  43.     fclose($fp);! P. e3 I# |; A# W2 P3 e
  44. 3 l% e3 P$ T7 g3 ~! d. d
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');0 t, Q5 D+ C1 {5 L& U3 M8 U
  46.     // while($row = mysqli_fetch_assoc($res))
    0 [2 f6 z8 O" o
  47.     // {
    & W0 `5 {# D8 E- T5 i$ m* A
  48.     //     $id = $row['id'];- ?2 M3 G- k  M" [0 D$ F7 n
  49.     // }
    5 [% p% T5 z+ b* n9 g
  50.     // echo $id;
复制代码

: S6 K  L7 f! q- b  ~
7 \9 ?9 K+ R/ U+ ?) O( c( v
抢券活动实例:
  1. public function envelopeSnatching(){5 ?- v" k) g% N0 G
  2.         $lingqu = $_POST['type'];
    3 B% T+ S9 D, B- J4 ~& E( \
  3.         $uid=session('u_id');//用户id. W$ [/ P  p: b7 `: B
  4.         if(!$uid){
    1 ~' R& \! E. P4 K( E
  5.             $data['msg']='您没登录,请先登录!';
    ; n; c! ^$ f5 I" i
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    2 `/ D% \3 K! V7 k4 T- z9 R8 i
  7.             $data['msg']='不在活动时间内!';
    3 w7 G6 u; D4 g
  8.         }else{
    9 s, y' z) d3 t0 v
  9.             $hours=date('H');//当前小时数% A8 t" B7 {9 \; j; T) l
  10.             if($hours > '09' || $hours > '17'){
    0 ?  _4 n: h- k4 p( {% P! w1 }

  11. 1 E. O- q% e/ v
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的( g9 W! Q; m( ^# D8 I
  13.                     if($lingqu == 1){4 @& E3 ?$ I6 ^" @) c8 q, i" G
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    $ ?; v3 N! f# t. F
  15.                         if($hours > '09'){( R# {: j3 D3 |: h8 ~  d9 H
  16.                             $num=mt_rand(25,28);//优惠券金额9 q! t# s: f* |8 @
  17.                             $id=1;
    - n6 U/ p# P" j
  18.                         }
    % Z/ c8 w! O$ t" E+ k. p
  19.                     }else if($lingqu == 2){' D- D6 B' x& A; u0 w9 c
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    ! o0 l5 G; Z( s! E
  21.                         if($hours > '17'){
    ( S4 f5 s1 |- K  ?
  22.                             $num=mt_rand(50,55);//优惠券金额
    % ~" y4 P9 P  m. c1 }
  23.                             $id=2;/ J5 G& `* U- n; y) W
  24.                         }  R/ y" q) b. O4 ^
  25.                     }' ]2 F/ u  D4 @1 K) |
  26.                     if(!$id){
    % l5 h/ h) ~5 Y2 K$ e- e
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    4 F- e8 K6 R2 [# f3 y& Y8 r2 u
  28.                     }else{7 W5 B, @2 u* z6 m. w4 b
  29.                         if($is_lingqu){; a2 ?. t; [' T
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';9 \% ^0 s" |2 M' z, E/ \. Z
  31.                         }else{
    5 }1 b1 M# p6 ^+ T5 r3 C4 Z- b4 a
  32.                             //锁表" [) b$ z5 q$ d+ b# g
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');3 B; }6 L4 e: Z
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();7 m: T+ `0 [# n1 o, T
  35.                             if($active > 0){
    1 `$ R8 q' {3 Q) g8 k4 W$ ^
  36.                                 //开启事务0 F# i) d9 F( l& B( K
  37.                                 M()->execute('start transaction');
    ' e$ P7 Z& L  n% l
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    & J( \. [9 U% ^9 p0 s% b
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));& c; R' s) V4 `2 x& B5 e. E2 m
  40.                                 $members_preferential    =    M('members_preferential');- Q5 M. p- T" ~1 ^7 T
  41.                                 //对应投资金额,5 x4 F* T' l) U8 t) w7 C- n
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));4 ^. j  Q8 |/ y  ]
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    - I, W8 J9 {. a; T
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间4 `: P% m* [* ?6 R9 _
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
      Z3 c7 `/ I* p% k6 X4 x
  46.                                 if($save && $add && $add2){
    ) a: `& E8 F; J2 D& [: Z
  47.                                     //事务提交
    ) M" q- \3 }# D
  48.                                     M()->execute('commit');
    / d  ~- N$ [( k0 i" F6 n/ c) O  _
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';, |3 A& \+ t  B+ Z& O$ N
  50.                                 }else{
    7 G3 K4 P) l7 y) ?" y. z
  51.                                     //回滚# G7 J/ B( i( ~5 S
  52.                                     M()->execute('rollback');
    . q/ R$ }. P0 Y& Q! Z: U3 t* ], n
  53.                                     $data['msg']='未知错误!';) i; q: s; s* `9 D. P5 J# Z" G& ^
  54.                                 }/ P$ @9 \. O% @; @4 v
  55.                             }else{' @! G  V; A$ c& h6 J) o
  56.                                 $data['msg']='红包已领完,你来晚了!';
    7 g. O! q4 _0 I% L- s
  57.                             }
    8 K8 |- l2 m3 _% W; L5 y
  58.                             M()->execute('UNLOCK TABLES');
    ! o# ~( C; |- M. D0 H
  59.                         }" o/ z( w! ]- d5 i
  60.                     }# O+ s+ t2 C( M! a6 `& g$ t
  61.                 }else{
    5 u9 {+ p& f. B# r3 v: f
  62.                     $data['msg']='非法操作!';3 O9 E" m# s& ^7 g
  63.                 }
    3 \- S# t+ w8 v' d: J( l9 u
  64.             }else{
    * f' u5 ]3 N7 R* w: r1 h0 t
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';$ O& @; f) a' ?; e+ T
  66.             }1 X) Z$ j5 m) M( t& j
  67.         }
    9 K( p* h* n" }
  68.         exit(json_encode($data));
    8 `# G2 Z7 C5 B
  69.     }
复制代码

+ I; ~7 G  _# L& c: v
8 Z9 l8 T: u& b3 f, V8 F
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 00:17 , Processed in 0.081819 second(s), 20 queries .

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