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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9872|回复: 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://请求的脚本
复制代码
' [" r3 D; t% Z( C, c  r9 o: E
Mysql中的锁语法:' d! U3 R, P( {8 H# P, q8 i- ^
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
& k: L4 Z/ L9 j) `$ ?UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表5 H. L2 b: J. \
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞; N1 d! z% g8 ~- p! i" V3 v- S5 G9 k
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :* |$ u  L0 r$ q1 e' `
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
  _% N9 e& M' [; {4 R测试时,有个文件就行,叫什么名无所谓
总结:3 P" M4 Z/ B; ]& k" _6 S: B
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:1 @4 o  _, P- W/ b9 Z5 N- P
1. 高并发下单时,减库存量时要加锁
$ A1 p6 S1 _$ x2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    5 _9 y0 q. Y4 g" G
  2.     模拟秒杀活动-- 商品100件( j- n2 U# _6 C0 G( n
  3.     CREATE TABLE ta; m9 c& {8 ]  u; R; B) t( l$ J: T9 f+ L
  4.     (
    " j! ]& E7 ?/ t
  5.         id int comment '模拟100件活动商品的数量'( \; ^6 h% v4 I! M: c$ Y) u0 E. `
  6.     );
    3 [* N0 H% p6 m9 a1 x
  7.     INSERT INTO ta VALUES(100);
    1 B, \5 o. @7 P) k
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    8 f6 x* N2 K+ }, t/ U# R
  9.      */
    7 @6 }6 r4 d" ^% O
  10.     5 V6 ^2 l8 A5 y  l: L  O1 n
  11.     // 关闭错误报告
    + q  l8 _2 m5 \% F2 y! t8 V; X
  12.      error_reporting(0); 4 ?+ G: Y& v+ h/ ]: i
  13. . J- c- [. ~4 D: Y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    & ^) x/ p* G/ ~1 a/ A4 F7 c) i
  15.     $dbuser = 'root';            // mysql用户名  b* ]/ u. F) k# S1 h% [# p
  16.     $dbpass = 'root';          // mysql用户名密码* ]5 g9 h0 E4 g! U/ {
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);) i' T( ?0 ?2 [$ i2 W" l$ b4 D* I
  18.     if(! $conn )$ G9 P! U' a$ m. J2 l- y2 Q
  19.     {0 i! \2 p7 q4 Q9 F$ z  ?3 I
  20.         die('连接失败: ' . mysqli_error($conn));
    2 t1 R* ]8 E( F2 _' s
  21.     }! L; S( s& R/ q2 ?
  22.     // 设置编码,防止中文乱码& [+ ]# F- e% ^$ Q) \
  23.     mysqli_query($conn , "set names utf8");! _# u9 i" B* e5 t; `( u& `
  24.     mysqli_select_db( $conn, 'temp' );
    5 g( k+ E; @' E1 [- d5 }( F8 p. _

  25. $ a+ _9 j1 i* z+ Y, X) K
  26.     # mysql 锁 % ?. A$ q% d% Q7 {
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    . @+ K! Q* d, c# D, J
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); . ]: ~- Y# L9 U
  29.     $id = mysqli_result($rs, 0, 0); . ^* ?" S3 ^# P0 {* _1 N
  30.     if($id > 0)
    / b+ U; T+ e' U0 [. \3 f% `$ @1 `
  31.     { 1 m& x% m+ T' g, k7 L8 [" i
  32.         --$id;
    7 H: j( \' K7 l6 T
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); & U. w+ n" \% p1 |' F) A# r/ T
  34.     }
    ' S0 X; ^+ q, n2 G6 d
  35. ) k8 H6 }, `' [6 x
  36.     # mysql 解锁
      J& S9 C. c3 O. ~% q3 t
  37.     mysqli_query($conn , 'UNLOCK TABLES');) O# R# d9 ]2 N3 W+ R
  38.     //查询解锁后的id值
    " b! `+ y* l, @) i9 U1 {
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');% d% S: N' ~4 ^$ X3 Q, p% |
  40.     // while($row = mysqli_fetch_assoc($res))/ O, W. ]3 s! E: q4 T0 g
  41.     // {- d7 w# u4 M' g' Z  s2 d
  42.     //     $id = $row['id'];
    % H! u. v- X! @2 E( I* m
  43.     // }
    : ]5 M) o7 B$ V. \  w9 j. L- M
  44.     // echo $id;
复制代码

- A; U4 n! V- {9 S2 v4 a
9 H1 e7 J) Z5 U" C1 }

: X3 u3 F! h' g- s+ E' ^" X# k
PHP文件锁示例:
  1. /*
    7 t# Q( f; B; C  t" Y* r. s, s
  2.     模拟秒杀活动-- 商品100件
    - w8 {  Q3 `' J& j+ x
  3.     CREATE TABLE ta
    , C- m# I9 ?4 |( y# c
  4.     (
      v6 j0 N+ h4 r
  5.         id int comment '模拟100件活动商品的数量'
    ; m8 D5 v0 Y1 p* \/ g
  6.     );
    . j1 s  T4 H! v" b
  7.     INSERT INTO ta VALUES(100);
    3 b+ c  i2 C( B' a" y! X5 ]5 u9 g
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    $ J/ Q% d2 X$ d) F- i6 w6 G8 K
  9.      */
      T& k* e3 h* [4 b
  10.     2 G2 V8 c" S  q! }. ?
  11.     // 关闭错误报告2 u& G  ~( q* L! a* v
  12.      error_reporting(0);
    ! u/ d9 O: _7 h% n5 X* e
  13. 5 X+ \( W" z% z
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址: y4 ^2 o6 O) U5 A! ^" m
  15.     $dbuser = 'root';            // mysql用户名
    ! k3 T5 `& U$ e' M6 z% X" {3 W
  16.     $dbpass = 'root';          // mysql用户名密码
    ! a5 w; Y! F8 i3 Z, k& N
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    * x+ K" ?' ?# E' L
  18.     if(! $conn )9 p/ g, C- {# e3 V4 b
  19.     {
    & e2 U) x5 g" n9 I4 A1 M- D7 e) t
  20.         die('连接失败: ' . mysqli_error($conn));: M. E: m' w+ g( ~5 F, n. y/ c
  21.     }- ]6 B! g- J( G% A
  22.     // 设置编码,防止中文乱码
    4 c  H; W, }4 Y* `  O
  23.     mysqli_query($conn , "set names utf8");6 b8 j" k% E/ R. O# V3 Y! E2 a
  24.     mysqli_select_db( $conn, 'temp' );
    & a  G. J% q" _' C5 v

  25. * Q  S# P8 C8 w( j/ R  R
  26.     # php中的文件锁 & a$ V# g0 t2 W( ]6 n) d
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 ! ~! ?6 i+ Z( Z
  28.     flock($fp, LOCK_EX);// 排他锁 + `2 `9 e1 q/ v% d& y) C
  29. 8 Y: c# a; e; G+ W5 ]) W# n
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ' W" n% w3 M7 K" @
  31.     while($row = mysqli_fetch_assoc($retval))
    7 o4 A5 u2 z$ R, o; a( o
  32.     {# u" ^# Y% k; E  u$ C* B1 I
  33.         $id =  $row['id'];
    6 e5 o% z& W. N8 V) O8 L
  34.     }
    3 f; n2 ]! a8 Z- U0 c+ q
  35.    
    " Q+ K! o* R; X5 w
  36.     if($id > 0)
    ; @) A5 j) G, G
  37.     { + ~& o% o3 _9 ^9 n, d
  38.         --$id; $ b# _. x% f/ U9 h$ h
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    7 z/ b- B7 e  Y. E, t9 F
  40.     }
    5 ^4 H  V" c( G0 W
  41.     # php的文件锁,释放锁
    * M# t) Y% Q" k, ]/ H* e) o
  42.     flock($fp, LOCK_UN);
    / e% r, z( e* X  f7 o# ^. z
  43.     fclose($fp);
    ! z& K7 L  N2 o
  44. ! x( f. K+ Q8 ]* D
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    - ?. X7 J. p" y6 @2 c! N( e$ a
  46.     // while($row = mysqli_fetch_assoc($res))2 a4 p: m5 U' z% y
  47.     // {
    / O. \$ i% A3 d# |5 L/ D
  48.     //     $id = $row['id'];
    " S7 N; P8 `- C# ^. _+ ]  f" T
  49.     // }
    8 ~; x0 \5 U5 a8 ?# f5 J
  50.     // echo $id;
复制代码

' S6 U: Q9 A3 l* K" O, L- Q+ @5 {9 E0 I& e, j0 k% ]
抢券活动实例:
  1. public function envelopeSnatching(){! ?& F. p0 U5 S
  2.         $lingqu = $_POST['type'];
    ! I! u& ~% o5 E1 b' [7 \
  3.         $uid=session('u_id');//用户id8 X2 i) d0 T* y  j
  4.         if(!$uid){
    7 f. l; g" o9 B: ]
  5.             $data['msg']='您没登录,请先登录!';: E/ w: |* ?" j( c
  6.         }else if(date('Y-m-d') != '2017-12-12'){' u9 L2 n8 E5 r% h
  7.             $data['msg']='不在活动时间内!';
    " U/ h% B9 B/ ^* Y5 @
  8.         }else{
    , p# N' t$ d7 z8 O" ?( F
  9.             $hours=date('H');//当前小时数, j. F1 l4 [  H( U* `3 ~( u/ R
  10.             if($hours > '09' || $hours > '17'){
    0 I. K( g% I# u! [; J7 l0 z8 S8 t
  11. % c0 x- Z) F, K- v8 B# h4 F" }
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的% d2 R- w- j: S5 @
  13.                     if($lingqu == 1){3 K6 s( H( W, }) c; X& L* W5 g' |) B
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    7 {6 n1 Q7 I2 f, E
  15.                         if($hours > '09'){" y6 |4 V1 Z( O
  16.                             $num=mt_rand(25,28);//优惠券金额
    % M* w# }! ]/ _
  17.                             $id=1;
    - t$ U9 Y9 A0 j: k8 {# i
  18.                         }6 d* a" U, K' ], P+ `6 _2 v* X" Z6 L
  19.                     }else if($lingqu == 2){9 E& k2 T- U: k: M6 S( d7 q! o
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();9 S- e1 q! ^" _, L
  21.                         if($hours > '17'){5 ?; R$ u% ~$ p* m* J
  22.                             $num=mt_rand(50,55);//优惠券金额+ o! ]) m1 o0 E& n; e$ Z
  23.                             $id=2;. k; J6 r4 ^* x
  24.                         }$ U" c" ]8 _5 n$ D- B! v: W
  25.                     }. y. h2 A' A* s
  26.                     if(!$id){4 g7 D* m- a1 s* Z2 y2 H' u
  27.                         $data['msg']='时间还没到,晚点再来吧。';0 [: ?5 C8 p' ]0 B. B! t  w
  28.                     }else{$ F* m$ r$ b8 x/ s1 E
  29.                         if($is_lingqu){, C: E) P8 c4 ]& e% f' a
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';4 \- @$ G* \3 z
  31.                         }else{8 s% L- S: t9 H' p, U( r6 `" g
  32.                             //锁表  W" a5 b0 l* N( X+ \+ ^* O
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');) g" \. y6 U* R1 H
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    * R; e) w6 g5 _
  35.                             if($active > 0){
    7 S7 S5 H3 n: ~- o" w
  36.                                 //开启事务( O, J# Y4 D. E) V# z- s4 L* V
  37.                                 M()->execute('start transaction');
    $ ]) k5 I( X& {2 B+ P" O
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    2 ^- C5 r7 y- l
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));+ M, X$ Y9 C% ~
  40.                                 $members_preferential    =    M('members_preferential');. [. O1 X3 {: C0 N6 {8 |5 _
  41.                                 //对应投资金额,3 Z9 [. i4 b$ e) l8 M
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    9 m; O) y/ `9 n3 f4 i
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');) e8 p% H# H, Z, B9 v5 h6 f  q
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    1 f4 P, _% _3 A! i1 j% A' S3 r
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券" y+ E+ R! ^2 V+ P! M( a; U
  46.                                 if($save && $add && $add2){
    : H" ^* m7 _& `  o
  47.                                     //事务提交
    % g9 j3 t- |/ c7 n
  48.                                     M()->execute('commit');) ]" z' b: o; f5 b6 L  r
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';7 R+ x$ F8 c& a0 y' \( F
  50.                                 }else{+ R- _" V4 x5 R4 j9 T9 S
  51.                                     //回滚
    8 b; C( o+ v) s* N  w
  52.                                     M()->execute('rollback');
    " L/ ^) G3 j0 d% l% o$ k3 K& o
  53.                                     $data['msg']='未知错误!';
    % ?6 t0 N, q4 @8 v, F$ C" r
  54.                                 }
    ; o& E! l: ^) p9 ?. @
  55.                             }else{
    ( K" x7 f- G* u" a  E  }' L1 h
  56.                                 $data['msg']='红包已领完,你来晚了!';+ F' M3 W9 f6 z, n) W& s4 a
  57.                             }
    6 l# J- t- @6 o* p# _5 O
  58.                             M()->execute('UNLOCK TABLES');
    : I$ W1 V/ @+ e+ m7 C( g
  59.                         }
    + j# q! p2 I$ d" q6 @
  60.                     }
    + e) m' A* v7 G: P4 i- h2 g3 ?& {
  61.                 }else{0 {7 T; c8 V$ S: l0 C9 l5 A
  62.                     $data['msg']='非法操作!';( |: T% t7 t8 R
  63.                 }
    + e6 K. F8 k# T6 u8 O7 _
  64.             }else{
    ) D7 {5 G! T8 S* k5 B/ ^( W
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
      k  b& ~$ D8 K8 w: `$ ?8 f- Y
  66.             }3 M3 r" g8 q9 L5 Y1 m+ X
  67.         }
      b# G$ P" P; f6 v5 F
  68.         exit(json_encode($data));  B, Y2 S" C' }# P: I" v/ v/ r
  69.     }
复制代码
! {0 {, t5 [$ a6 S, X* d
; K4 I5 s/ E) q+ v7 L+ [7 j
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 02:05 , Processed in 0.058500 second(s), 20 queries .

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