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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

# q" \' u! Q2 P# S2 S: S
Mysql中的锁语法:
2 l9 O9 j, O, l+ L! n) W) lLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】1 r' p$ g! P7 h, @4 h
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表/ l! X8 y( E8 R' X" O
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
' q6 S, F1 p" X, a注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
6 k8 y3 L9 J' _# a文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。8 k3 f/ ]# e2 i2 [
测试时,有个文件就行,叫什么名无所谓
总结:& I! A4 M+ t7 D
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:& d) K' v2 j  y- I1 r& o5 H
1. 高并发下单时,减库存量时要加锁
# k* T0 d5 q) T/ L6 [4 Q2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
      c' p% r, ?) v) l  a! O2 r8 }4 v9 z
  2.     模拟秒杀活动-- 商品100件, h8 b* |- [/ ]& v1 W
  3.     CREATE TABLE ta% h: x2 m" Y& n) c% a
  4.     (
    ' J1 Y! U1 D$ ^4 B: r: {; A' u
  5.         id int comment '模拟100件活动商品的数量'( `1 f8 D- X- R, S4 A: i1 N
  6.     );8 c) P4 V3 y7 x8 a' x  M! G
  7.     INSERT INTO ta VALUES(100);
    / S! R' Q! x  \
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件: z  G+ M# U0 P; M, i, I
  9.      */
    % l7 u' R3 P. m  C0 m( @; S& ~+ \8 d
  10.     $ ]  w$ H! V( f3 X  U; g
  11.     // 关闭错误报告
    * K4 Z3 n6 F* c  E
  12.      error_reporting(0); . b, e, V# `8 v" W
  13. " W" D$ r6 [/ ?, W% }
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址$ v8 m1 K1 @2 u! ]
  15.     $dbuser = 'root';            // mysql用户名2 R& U1 X) W6 a" I6 I8 X
  16.     $dbpass = 'root';          // mysql用户名密码
    ( k& z0 j+ U- _  J+ `$ D& T
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);  p8 C* s7 g. S9 z9 g
  18.     if(! $conn )
    * i0 S; n! G7 z! f# H; i2 P0 w2 G
  19.     {
    - s4 _9 j7 q5 {( B# q
  20.         die('连接失败: ' . mysqli_error($conn));
    ; F+ ]. ?, Q5 D0 D0 G
  21.     }1 u  k" ?% n0 ^% j. f! G" l! D" [
  22.     // 设置编码,防止中文乱码
    3 T  ^( R4 _/ ]# ^: Y; U
  23.     mysqli_query($conn , "set names utf8");
    ( k7 ^& o4 A2 p1 S7 N0 W+ D
  24.     mysqli_select_db( $conn, 'temp' );
    , X  \7 d6 |" ?& |" p8 x' O

  25. 3 K/ o9 |; P* r2 t
  26.     # mysql 锁
    # @9 S" r9 \& s( M  b% [% L9 x% g) D0 P5 W
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 * R, E) f. k; h; s
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 2 [- T; ?( q' @& W) k, M
  29.     $id = mysqli_result($rs, 0, 0);
    5 w) I7 `9 H" l) |) ?3 L
  30.     if($id > 0)
    4 b1 v% J' ?1 P# o* D; A7 C: T
  31.     { 5 }' O  X) ?8 x7 p1 |
  32.         --$id; 0 w" {8 l) q3 N. ^6 M* O
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    ( {1 O! E% m* j) l% N* G! G5 b
  34.     }
    8 Z' N3 E0 g. u

  35. $ s& b  T8 _! p% J4 T9 p0 D2 z, u
  36.     # mysql 解锁
    , J& B; g# i  o# f& u8 ~+ t
  37.     mysqli_query($conn , 'UNLOCK TABLES');) _4 t2 B4 i9 p( R& x# e$ l% V
  38.     //查询解锁后的id值
    * E9 g8 Y8 _* ~6 B5 ^
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');5 l. h3 t9 f0 J* ~( p. z
  40.     // while($row = mysqli_fetch_assoc($res))8 H( s, T+ A- I2 @, n
  41.     // {
    ( R/ \, f+ {5 b7 \4 w; Q
  42.     //     $id = $row['id'];" G% Y7 X, Q; [3 \
  43.     // }
    & X& S: I* ]" k1 [$ l; ]) }2 ?
  44.     // echo $id;
复制代码

; t! ]7 [2 O4 i/ E: E# C2 x
9 D, a) \4 {' V- `: Z7 H3 O! J
) O* D( H7 ^  ?7 S* `
PHP文件锁示例:
  1. /*
    # R! Q* V- t" u: w  I
  2.     模拟秒杀活动-- 商品100件) l3 N- T: I- a: I
  3.     CREATE TABLE ta6 _3 y) Q* X% l0 N+ D. R3 R
  4.     (7 [- J6 A/ d  }9 \( n
  5.         id int comment '模拟100件活动商品的数量'4 @4 w2 Y2 D' I2 j2 N) |( j
  6.     );! P% J1 o8 u- y  y3 U& x, j/ y; P
  7.     INSERT INTO ta VALUES(100);
    - y& y: X- u+ @' F, Z! }$ H7 B; U
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件% j, ^) r7 j1 q% _- A) D, j% G
  9.      */ ' F3 e2 N& r+ g0 O
  10.     ; h2 H0 U# C- }2 V+ ]3 z
  11.     // 关闭错误报告- v- `  W$ @8 W% O2 P( [1 Q6 b
  12.      error_reporting(0); 2 w6 X8 @4 b4 t. i5 q& o  ^

  13. 0 F( q2 X  N1 U$ E7 j/ a$ G5 g0 y5 `
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    5 F# m3 K$ ~& Y
  15.     $dbuser = 'root';            // mysql用户名
    & [2 W$ ~9 k+ A! `$ f7 w
  16.     $dbpass = 'root';          // mysql用户名密码5 N2 I. l: @! M6 M2 v( b- d# p2 t
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);6 y. }1 H( T* a7 {1 O% q  a
  18.     if(! $conn )
    0 ]" `/ u; o8 g5 W1 ?- m( h4 S
  19.     {6 U: o% ]. w# F' t3 z- `3 e
  20.         die('连接失败: ' . mysqli_error($conn));
    ' X- Y1 q( @. u8 I/ v  u5 a6 Q  v
  21.     }
    8 n( O* M( H' q2 P- G0 q
  22.     // 设置编码,防止中文乱码2 x- S- F+ }( _: e6 ^7 K0 H
  23.     mysqli_query($conn , "set names utf8");* I( L8 E* s2 m: _: _# ^! D
  24.     mysqli_select_db( $conn, 'temp' ); 4 ~% L0 R& q7 a& L/ U

  25. 3 y$ J1 k/ }, W- ?) n
  26.     # php中的文件锁 - w; z" C; L8 g9 K8 q% v
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    # ?; K% ^  b( _& y( G
  28.     flock($fp, LOCK_EX);// 排他锁
    - s' z% |4 U/ d3 e9 [6 x

  29. % _3 Z7 i, K* X! ~
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    5 P! w& q1 ^1 ~( t0 y: o' x
  31.     while($row = mysqli_fetch_assoc($retval))
    7 Z7 a' }; q- H; e, ~/ f, N4 f7 w
  32.     {
    # O' d3 D/ N; y1 D. |& T4 G
  33.         $id =  $row['id'];& K# _7 `( E. Z" V+ L5 e5 [
  34.     }
    2 E  g1 E2 p' Z% Y  t7 H
  35.     . W$ ^( f) I1 h. U0 R7 [1 K+ f" d
  36.     if($id > 0) 3 z' N; F7 I' {5 U$ V8 F
  37.     { 5 K$ i8 L8 }* n* d4 o8 H, m0 d  `
  38.         --$id;
    / E4 [2 H7 U1 x, v* z/ X
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); , P9 v# e6 c) l1 }) J
  40.     } * v% u% y: f- y5 w* x
  41.     # php的文件锁,释放锁
    * P0 l. H. K2 b% K* l4 Y, K* L
  42.     flock($fp, LOCK_UN);
    % v0 p2 x/ |  B1 H- Y( o8 O- {
  43.     fclose($fp);
    / i8 t. h7 i4 {: p; g

  44. ) {7 x9 v$ o$ {/ S, a, Q
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ' B7 j1 g  H9 S
  46.     // while($row = mysqli_fetch_assoc($res))
    # ?+ Z6 X) K" l; S" `
  47.     // {, S; w0 d+ C( b
  48.     //     $id = $row['id'];
    6 {5 X0 e& R& `; ?% o
  49.     // }" U6 M! o' C% q7 m5 _: Z( Z
  50.     // echo $id;
复制代码
$ x3 Q% Y8 ]" l, O
$ s. W5 o2 o( S
抢券活动实例:
  1. public function envelopeSnatching(){, F: Q* h+ v- Z: l& @$ Z
  2.         $lingqu = $_POST['type'];
    3 |/ `' d# q+ C! M
  3.         $uid=session('u_id');//用户id
      U6 |! h: G! }( ]3 G$ d" U: z
  4.         if(!$uid){
    1 A4 K# Q1 I' u4 j! x) q+ G9 @
  5.             $data['msg']='您没登录,请先登录!';) U, ?! s$ \6 i* |9 \2 l4 E; D
  6.         }else if(date('Y-m-d') != '2017-12-12'){; {0 e3 W+ Y& o
  7.             $data['msg']='不在活动时间内!';4 e# ~6 J0 \2 Y$ x4 x4 z
  8.         }else{
    : f8 E4 p- r0 l- S
  9.             $hours=date('H');//当前小时数5 ~" ?9 U) \: @1 J  K$ g* n# p: Z
  10.             if($hours > '09' || $hours > '17'){; a$ a# s3 D2 y; e
  11. 7 G/ |6 q7 x1 o4 U7 ^7 @, `
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的" R1 O3 z6 ?* J( z5 W
  13.                     if($lingqu == 1){5 Y0 H9 U% ~3 N. @, K7 D0 H* D
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    . S* t  w" T- u! g/ o2 w
  15.                         if($hours > '09'){
    . H8 m. F% d: F6 f
  16.                             $num=mt_rand(25,28);//优惠券金额1 ]7 x. \, B4 s
  17.                             $id=1;5 N- v3 ^$ B! \) r2 g+ a
  18.                         }4 H* V* \' K! H/ b* R
  19.                     }else if($lingqu == 2){
    : h1 A! f8 F7 e; T3 R3 i6 f
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    ! ^3 O$ y: A, E$ d" Z+ b" |
  21.                         if($hours > '17'){
    ) M& |) O! n/ E
  22.                             $num=mt_rand(50,55);//优惠券金额
    / n0 U" y# a7 @* T3 N* b& z% n
  23.                             $id=2;
    & f# u2 L% Q4 ?' r/ v4 T6 J; S
  24.                         }% i  P# L# E$ Y/ r6 C
  25.                     }
    & o/ _: [3 [3 _. u5 H) r7 H
  26.                     if(!$id){
    2 d+ p) O6 u0 [1 F$ P/ Y1 J
  27.                         $data['msg']='时间还没到,晚点再来吧。';* ?8 Y% I5 M0 E; G9 ~2 @( D9 m
  28.                     }else{' T" G% Y3 H0 h
  29.                         if($is_lingqu){, N$ M; t$ @1 q. c$ u! W+ ]; a6 A
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    ' u1 g% o6 ^3 n) d% e2 w+ e
  31.                         }else{
    ( g6 N& x- m" A" C! Z
  32.                             //锁表9 z3 E8 d: |% J0 q1 P# B
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    4 y0 N/ A4 O- R! k, r* I# n9 y
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();' B  I$ @- x9 g0 M6 ]
  35.                             if($active > 0){; p! v$ K& c, q, t
  36.                                 //开启事务
    4 E4 S5 p2 B* |. `
  37.                                 M()->execute('start transaction');
    * H# D8 c! ?/ |8 @+ y9 h
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));& E- V; v' t4 ], r1 @
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    8 j, F! r  w8 _' K4 S1 J
  40.                                 $members_preferential    =    M('members_preferential');, e5 N3 Y+ s% q% ?( g  U
  41.                                 //对应投资金额,
    ' s8 H. w9 |" I( Q) b8 i2 L5 @
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    5 x* B/ [+ p! [# O3 s
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');( v- ]: x) p. ~! z% I$ T3 ^. U8 D' i5 k1 C
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间6 K7 T  ]/ x- A0 ~( Y* B0 W9 F5 U$ ]. W
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    : g, ~" E5 D$ F8 c# u+ x% g
  46.                                 if($save && $add && $add2){
    & ]) P* N8 Y' O
  47.                                     //事务提交
    & [* V& A6 K( X; ^% q1 D' S
  48.                                     M()->execute('commit');8 P7 N1 z% t- I) G
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';9 e6 M1 ?, J9 j# I4 ^8 c
  50.                                 }else{# z4 g6 r( S( a- |' }  h9 I: }
  51.                                     //回滚2 I! E0 m9 V6 A6 W& h# l
  52.                                     M()->execute('rollback');
    5 J: E2 h; _' a0 B
  53.                                     $data['msg']='未知错误!';
    7 t) d+ t9 w4 |0 M' W9 Z* K
  54.                                 }0 _7 E! Q; S2 o5 M: ?. c2 q0 k9 S
  55.                             }else{
    " L$ t* a) @! X) Z6 M: q* f: d
  56.                                 $data['msg']='红包已领完,你来晚了!';
    0 k$ A8 v) Y$ c2 a
  57.                             }, ]: y) N1 i  T* P
  58.                             M()->execute('UNLOCK TABLES');
    0 o. @; x' J/ L2 g
  59.                         }4 s8 T) L; `7 D
  60.                     }, F7 m1 E- G! J8 n/ f) C
  61.                 }else{! M, n2 F+ b! N
  62.                     $data['msg']='非法操作!';
    ! `9 L6 R1 U9 E7 c0 N2 \; P9 `7 s
  63.                 }
    " j, c' m- I7 ^
  64.             }else{
    0 I+ \9 {- \* g& W+ e( l& c
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ' J5 ~3 b6 X' Q3 h) n
  66.             }/ a3 ^/ U8 u) m1 \
  67.         }7 q3 v' R  _1 y$ Y" y8 j+ ^6 b
  68.         exit(json_encode($data));. m2 f- L* ^5 A) s4 i/ o3 E* |3 N) i& Q
  69.     }
复制代码
- V6 e+ z, F0 [( J- v
1 l/ x. O( O1 E; P. {
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 12:58 , Processed in 0.058247 second(s), 19 queries .

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