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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9109|回复: 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://请求的脚本
复制代码
0 L, M+ s) F# `4 i" b+ ~' V. ^7 [
Mysql中的锁语法:5 y$ F9 u/ C, V7 N, l1 ^* ~
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】& }; X# w6 q* F/ G
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
: Y5 v8 c" r2 B; i. T$ {/ RWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞- L, ]% v4 `' g
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
- e$ p6 ~# X$ o+ p8 L/ J8 f2 R& w文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。5 q" w, W; H5 j5 f
测试时,有个文件就行,叫什么名无所谓
总结:
/ d" d5 K/ b; _/ M- ~项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:; u" M$ k; p+ k; F: A7 u" T
1. 高并发下单时,减库存量时要加锁
# ]( `/ F1 H# i% R' a: p" v2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    + Z. M, V: [0 s  v2 @' d& a
  2.     模拟秒杀活动-- 商品100件
    " b. r8 q' i6 A7 }5 I
  3.     CREATE TABLE ta
    , [. p' K) J5 b8 d0 Z
  4.     (
    2 a$ t$ g  ~; y# \+ {
  5.         id int comment '模拟100件活动商品的数量'
    4 l1 r9 C5 f7 ~, }8 g7 M( c+ k" `
  6.     );& z" k! D0 _, A1 {$ c5 R* F
  7.     INSERT INTO ta VALUES(100);
    ! w$ g' @, G5 Z: |0 O2 V' d
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件% _" h% H4 W; J; Q9 A& I% n, n
  9.      */
    , G9 ?) v. |4 i* \% g
  10.     , @: X2 ~. G0 c. q4 a5 B4 Z
  11.     // 关闭错误报告
    6 B, G. h- R* w) N* H: b
  12.      error_reporting(0);
    * f% K' C5 ?* a0 C

  13. 6 P7 Q. g$ d5 ^3 [% P
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    7 G/ U- a4 c2 W0 V5 _9 c
  15.     $dbuser = 'root';            // mysql用户名
    : w0 l! Q4 ]; M" g4 n) D. `( y; N
  16.     $dbpass = 'root';          // mysql用户名密码5 w. k' M0 W4 i5 R) B
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);2 [7 v% Q7 u$ U, j+ K
  18.     if(! $conn )
    ' F9 O. [9 Q* L/ \+ U
  19.     {
    2 W+ J0 I2 [% c' h% w. ]# g
  20.         die('连接失败: ' . mysqli_error($conn));
    ( N8 {  F% `. R
  21.     }, Z0 ^# }% L8 s$ T0 [. G" u
  22.     // 设置编码,防止中文乱码0 j9 l$ Y. i, o2 N3 e% z, O: ]
  23.     mysqli_query($conn , "set names utf8");
    ( x* R. L3 ?" u: ^; A% B
  24.     mysqli_select_db( $conn, 'temp' );
    0 Q6 I/ K( F( d8 o2 e$ P" l
  25. ! y! x0 C) j. B4 U% }" v' m
  26.     # mysql 锁
    5 l( g6 ?' w9 L2 }
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ( E$ r; [" u3 y. a( M4 G& f, G3 L
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    + i- F( P5 H1 b8 |2 @
  29.     $id = mysqli_result($rs, 0, 0);
    5 ?5 O: t' Q# u: a
  30.     if($id > 0) / f8 P# e, x- C8 M( v
  31.     {
    6 M/ C1 F& V+ X' I# F
  32.         --$id;
    & B! Y5 t$ {8 R: P
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    ) q, x1 W, I" m7 i5 Y) X
  34.     }
    5 |. t* \# s- ]& l, W" E/ t" p
  35. 3 K  g; j( c1 w( z
  36.     # mysql 解锁 , w4 F4 p. V2 r1 f- y2 B& x
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    * f+ @, W* q9 \: n
  38.     //查询解锁后的id值" L+ t2 _8 a* Y6 ?9 w  O+ W
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    1 U, R9 V$ z+ d* J% R9 T- ^
  40.     // while($row = mysqli_fetch_assoc($res))
    , H2 s* Y" \# p, V' {
  41.     // {
    " O- z1 o7 ^; `+ x
  42.     //     $id = $row['id'];
    7 b0 S: `0 r7 f
  43.     // }
    ) F" b# v5 o( T7 O
  44.     // echo $id;
复制代码
$ P5 ?4 a0 b& R0 ?) [

6 n% P: D( T6 H0 K! [( t+ l

1 s9 y& v: f2 X8 ^- m# H, D
PHP文件锁示例:
  1. /*
    8 @7 h, D* G# Y1 ^2 m
  2.     模拟秒杀活动-- 商品100件- ~7 i) {' L+ H% h' m5 p/ l* c
  3.     CREATE TABLE ta
    ( K6 j6 B- K& M" m) [( S
  4.     (7 X% I$ W) ?* M5 u
  5.         id int comment '模拟100件活动商品的数量'! R6 C" A  V# b) Z9 i
  6.     );
    ) X! m+ b  S3 i& z
  7.     INSERT INTO ta VALUES(100);
    ! w: ~3 C' a1 l9 l
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件$ P9 u9 k" d" G. Y6 ^! @0 c6 ]
  9.      */ 4 `. |2 _+ D+ i7 h
  10.     ( P  t) y% E* y2 `
  11.     // 关闭错误报告
    - t" {: Y7 S; J8 W: ?' E
  12.      error_reporting(0);
    0 b% [) H9 _+ ?
  13. ) K5 f! e2 t! |  C% M
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    / Z1 r* `& R* \1 D1 s+ P
  15.     $dbuser = 'root';            // mysql用户名
    ' }6 H( V+ T0 d( a  V; }
  16.     $dbpass = 'root';          // mysql用户名密码! m1 R$ V; P: l$ e( u1 b  {1 t
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    . ~* C/ b& D, E! B1 p
  18.     if(! $conn )
    0 b  m& m! P2 S4 \8 d8 x8 }' R) g
  19.     {
    8 T! K; r( l" p: ]+ |" D) g
  20.         die('连接失败: ' . mysqli_error($conn));
    , [; x( W$ {" A5 d9 U- _# j( N
  21.     }
    8 S5 J* _: p# s, f+ k
  22.     // 设置编码,防止中文乱码
    + c1 m9 [" F* E- o! k
  23.     mysqli_query($conn , "set names utf8");
    / S! y* }6 L3 @" B1 ]7 Q
  24.     mysqli_select_db( $conn, 'temp' ); % k8 L# G% T$ J: y0 x9 C

  25. $ l$ [& h8 ~1 h3 I( T1 a, M$ H1 P
  26.     # php中的文件锁
    ( y4 N- a' @; A* }
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 ) |1 w! G& d2 ^$ ^: K7 B
  28.     flock($fp, LOCK_EX);// 排他锁 / J6 E6 V1 L  {0 K7 ^% I
  29. + Z. r" X) L, o9 a
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); " [' E) l% I) I1 A6 ^- p
  31.     while($row = mysqli_fetch_assoc($retval))) t8 \! s( w% i1 }0 A- e/ N# U
  32.     {" z  J/ q( }3 r$ X
  33.         $id =  $row['id'];4 k8 R4 G- R' I( G0 R; B9 }$ U9 s
  34.     }8 p3 p+ t  s& |2 f  c5 s( m3 a
  35.    
    3 c+ F+ [0 I6 _% y# s1 u6 @8 A! m' l
  36.     if($id > 0) : W1 s9 w/ C' S' b' F, \
  37.     { ' X& t3 ~" I( s* X  `, i9 Z, a
  38.         --$id; + C7 ^+ ]5 @) C3 z- O% U
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 8 X4 I; z7 m3 A8 N& S, @3 J
  40.     }
    ( @6 Y) [( s3 d, [$ b
  41.     # php的文件锁,释放锁 ! m  D0 ]+ q3 D' {/ n$ J
  42.     flock($fp, LOCK_UN); $ z% Q. P0 b0 Z3 ^, z# L
  43.     fclose($fp);. F7 o* ~; [6 ?* |9 n

  44. 5 R3 w# e7 i9 i0 N8 @+ r
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');5 k4 V- W9 V3 h4 v+ D& S
  46.     // while($row = mysqli_fetch_assoc($res))
      [+ E9 |  J5 p" g0 @
  47.     // {" n* R$ }; w. Z- ]2 E
  48.     //     $id = $row['id'];
    3 o  V2 [( g8 W. f& b- w+ M/ {, n6 S2 H
  49.     // }
    0 C9 k3 l- j, E
  50.     // echo $id;
复制代码
7 v* R$ r3 `0 L, n
/ R, ]6 H% h; U7 F" p8 t
抢券活动实例:
  1. public function envelopeSnatching(){
    : P3 ~6 t4 U, ?2 U6 G4 Y
  2.         $lingqu = $_POST['type'];$ X& M3 N2 Z& A6 J. `- w, A
  3.         $uid=session('u_id');//用户id
    # M% S# D; {1 ~1 O/ O
  4.         if(!$uid){6 o0 G$ R1 ]& N3 `( J6 K$ S/ Q
  5.             $data['msg']='您没登录,请先登录!';) Y# e" b/ S- l! P
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    4 e: ?/ G. L% ^6 d6 s# @
  7.             $data['msg']='不在活动时间内!';  G+ Q# }& k' o- K3 f
  8.         }else{* [3 T" Y, q2 v5 n; F
  9.             $hours=date('H');//当前小时数
    $ a' H. b" V( \; y; t* b
  10.             if($hours > '09' || $hours > '17'){
    1 z  V9 h+ e, e- y+ }
  11. 9 O3 R( x1 e; Z/ s4 X
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    . G" g6 t' y7 `: M$ o
  13.                     if($lingqu == 1){
    + S% w8 n- W/ L/ n
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过# @: d' M) D6 L5 N+ p4 U- I* `
  15.                         if($hours > '09'){
    8 t( g% ]3 @, w; B. D
  16.                             $num=mt_rand(25,28);//优惠券金额
      R8 m3 e8 A$ q' x" E
  17.                             $id=1;
    ! r  m- ?+ E* T  V& ]
  18.                         }
    . r; k, [# W4 S0 J& P
  19.                     }else if($lingqu == 2){
    : w  D) Z9 [7 i
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();3 A1 |6 c9 v7 ~( {1 \
  21.                         if($hours > '17'){
    , R" w; D3 g/ E+ l& Y5 R
  22.                             $num=mt_rand(50,55);//优惠券金额: e1 X. ~. ^3 q$ S  j8 z8 H- t
  23.                             $id=2;
    3 w4 a. U! }& s$ z9 m
  24.                         }: [; O1 b" m3 e1 e- d$ [- \/ v
  25.                     }' L9 E) g) O2 h4 }  L
  26.                     if(!$id){
    , Z; [% r# c" ~! z- S' w8 O
  27.                         $data['msg']='时间还没到,晚点再来吧。';
      e' ?- k5 y% b. C
  28.                     }else{
    9 e! C+ m9 Q8 N
  29.                         if($is_lingqu){$ \" V5 n/ N) x" x* M# ^8 h- m" }
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    2 r6 ~/ ~: x, L. ^" G3 u
  31.                         }else{
    5 {  K/ K. x' N& p9 h  l
  32.                             //锁表
    5 o; L- Z/ X4 n5 z2 M" C
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');% z! k% A' c# Z3 I
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();' Q6 t4 t9 e) [5 [
  35.                             if($active > 0){0 g# s$ m# m+ h3 X( u
  36.                                 //开启事务  ]0 ], Q& ~/ X' @
  37.                                 M()->execute('start transaction');3 u8 h$ d, |( X/ i% p/ R$ ?) R
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));4 @5 m& E- P, j) ]1 _
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));; x7 Q$ W/ S" h. V9 C
  40.                                 $members_preferential    =    M('members_preferential');
    , a7 z3 {% [% F/ e
  41.                                 //对应投资金额,
    7 F4 }* K. B% E2 n# Z2 S: Z3 t
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));- T- X  V7 c) `  e  Z: {
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');- q' @! D2 _2 d5 r
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    3 I/ Y9 V- r! w
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    % E+ m9 f* a  Z  `4 G& U- K' y/ K
  46.                                 if($save && $add && $add2){
    % M! a  D5 B) f6 p7 ^- F
  47.                                     //事务提交
    ; Q7 O7 F5 o/ z' F
  48.                                     M()->execute('commit');
    6 F- D' W! _# b( K. v
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';7 \" |7 Q( v/ D( l- P
  50.                                 }else{
    % f3 _' p" n8 W; M) }0 u% a
  51.                                     //回滚# G, m1 ?7 ]" W0 y/ |6 L1 M4 L4 V" ^
  52.                                     M()->execute('rollback');2 U4 q& I5 P; h; ^. [" T
  53.                                     $data['msg']='未知错误!';2 i" a) `( A2 t7 w3 k' L
  54.                                 }( B8 L4 K# I$ g" n
  55.                             }else{7 K( ?( J% m  j. ^% {% g2 V9 H
  56.                                 $data['msg']='红包已领完,你来晚了!';; c, z3 k" C# o9 S  Q
  57.                             }& V2 T0 {( x- R" U, b& j  ~0 X! \
  58.                             M()->execute('UNLOCK TABLES');
    # C7 }4 s# \% V$ P4 F3 S* V7 N' j+ d$ ~
  59.                         }4 s2 w' y+ D; _9 }$ |$ o( V! f2 c
  60.                     }( G4 [* ^9 h0 B
  61.                 }else{% D' S/ s; g; p: @
  62.                     $data['msg']='非法操作!';/ o- p6 h0 r1 [1 r3 E  |+ ~
  63.                 }9 c9 l5 Z! [1 _6 E
  64.             }else{
    6 @/ t& o9 v4 n' A# H9 y
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';& I4 ~+ |7 b( E; u
  66.             }
    . }9 b0 b+ c  ^( ^
  67.         }; p$ b6 w# v) [1 C8 x% |
  68.         exit(json_encode($data));0 j- v/ u* f+ L5 L$ a- d8 K
  69.     }
复制代码
: y/ w$ o+ }' e/ P: h+ i$ d2 R

3 m: a& _7 e9 q# d6 a' G8 O9 y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-7-19 17:39 , Processed in 0.059870 second(s), 21 queries .

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