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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

# g, H, y1 {. z6 @6 K7 p
Mysql中的锁语法:: l4 U) D0 d) k% f& Q/ B! \
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】- y  S7 E; W. h' ~# M
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
6 A! |- L- A+ n6 G3 r! j1 fWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
, H% t% y8 m; T- H) \9 A5 A注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :4 l0 l3 k( W  ~; w0 ]/ w" \0 ?
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。' |- o. n2 p& Y5 i1 k( s( Q
测试时,有个文件就行,叫什么名无所谓
总结:
$ Z5 \( P7 n3 P1 J项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
  i2 \$ d: T9 j1. 高并发下单时,减库存量时要加锁0 [8 R1 q% y6 @6 l1 }
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*- o. z3 G7 @! t; B. {% ?3 f
  2.     模拟秒杀活动-- 商品100件1 B' \% p- r' `  V( U/ Z$ c8 M
  3.     CREATE TABLE ta
    $ \3 Q6 x$ Z9 Q% p+ {+ \+ i
  4.     (0 R) x; M& L5 t8 T4 s" b& S% M7 ^
  5.         id int comment '模拟100件活动商品的数量'
      M4 `4 B$ S$ f- J
  6.     );
    1 I3 c2 Y  J5 ^& ?% U; k, N: s
  7.     INSERT INTO ta VALUES(100);
    * q* M9 C  z  W+ S0 l( J- o5 f/ T' |
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件! s* O7 `4 Z: N
  9.      */ ; a$ D% u4 ]1 ^( [
  10.    
    0 O4 k% _$ k( F: ^
  11.     // 关闭错误报告
    4 e" I% w+ q5 k8 B
  12.      error_reporting(0);
    7 ^2 V1 \3 d; N2 i; a& F
  13. ) D3 l  d- A) U
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    . e* H/ w8 p% S0 x! o+ H" y
  15.     $dbuser = 'root';            // mysql用户名
    $ N7 i7 g, k9 y2 f
  16.     $dbpass = 'root';          // mysql用户名密码
    $ Q( ~0 [+ ?- h: S1 M0 O* A
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);$ Z- Y, C' G* c& l* _: P7 M
  18.     if(! $conn )
    : R4 S9 l: a: h* b+ p" M
  19.     {  Y4 E1 I: S( a9 J
  20.         die('连接失败: ' . mysqli_error($conn));; c5 l/ ~) b$ h2 \4 W# `1 J
  21.     }
    9 n* P& `2 k( F$ i: J
  22.     // 设置编码,防止中文乱码1 W- B6 _' K) P' z, c
  23.     mysqli_query($conn , "set names utf8");
    % ^; X% q9 @" V
  24.     mysqli_select_db( $conn, 'temp' ); : u  W1 n6 ]3 Q* L( O8 d' T' K

  25. 0 V; S; R; M4 N0 j! K* M
  26.     # mysql 锁
    5 G; Z( E5 g; b" u4 j
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 5 E- e. h8 p* v5 S. P5 o  K
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    . t% d/ ?8 n8 b6 u1 t  ]
  29.     $id = mysqli_result($rs, 0, 0); - c6 T- h( }4 z
  30.     if($id > 0)
    . R% L6 A3 H6 |
  31.     {
    7 g/ Q% v9 s( q7 t3 }& F: V% E: l
  32.         --$id; . g8 Y' y1 t5 A2 X. ]& ^
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); + u$ F: K3 {8 e& d& P9 p; P$ L/ [5 h
  34.     } " `  p3 S. d" w# }/ D8 e0 {

  35. / T0 y) L3 o# D
  36.     # mysql 解锁
    . O9 }5 v5 B- X& G* A
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    + u2 z' B  n4 N( O
  38.     //查询解锁后的id值/ D  H7 w, F+ I
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');" r( T! j4 h4 R  A8 ]3 W
  40.     // while($row = mysqli_fetch_assoc($res))- {( G; V+ G: {: }5 _' A
  41.     // {
    ' ?) Y+ b! d" h( m! a
  42.     //     $id = $row['id'];
    8 x: V* F' M- c* i2 N8 C" _+ h
  43.     // }
    4 u0 w, }8 B( m( O5 z, W( d7 y
  44.     // echo $id;
复制代码
1 `' O7 O3 d5 r0 m# K" s
9 s: r6 L9 d; d

* w3 I9 K1 m- ]2 F4 K1 ?
PHP文件锁示例:
  1. /*& z0 x7 E1 j# g* W3 G
  2.     模拟秒杀活动-- 商品100件
    5 i7 G: Q: r, W9 C! |+ Q
  3.     CREATE TABLE ta4 w/ g1 J2 q2 g
  4.     (
    % O% Z& H6 i6 l
  5.         id int comment '模拟100件活动商品的数量'2 U& c/ F- F' h8 r# j% d8 u- l
  6.     );
    0 Y# W4 R7 E/ u
  7.     INSERT INTO ta VALUES(100);1 A& K2 b3 ~. ^, D+ A% M2 Y
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件- o& c4 U; U# b3 f3 X  c9 U% P+ {
  9.      */
    " G) j: N( N5 t* m: i5 `
  10.    
    4 r3 }4 j7 b& Q
  11.     // 关闭错误报告
    3 K; y8 o" u0 \! o- f( q
  12.      error_reporting(0); : b5 I6 f) o4 A% t9 R

  13. # M- M( ~3 Q. V# z7 D. ~
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    / r" }" P/ w: n0 n) Q
  15.     $dbuser = 'root';            // mysql用户名
      _4 F+ a' K/ d/ Y1 Y1 z
  16.     $dbpass = 'root';          // mysql用户名密码* ~2 o( {9 I  i9 \( J# ?$ z6 S1 n: l9 H
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    # f9 i7 J  G4 P# J& l2 p' P2 m8 a
  18.     if(! $conn )0 m0 F) p0 e3 A
  19.     {
    % G, ~# e+ D5 q
  20.         die('连接失败: ' . mysqli_error($conn));
    # |9 `* c: c' v5 v# G0 J* L
  21.     }7 P+ n+ B3 F- G2 j
  22.     // 设置编码,防止中文乱码
    ) X1 i! P% _5 R8 y) I. U
  23.     mysqli_query($conn , "set names utf8");
    9 K- F3 i+ q2 s+ |
  24.     mysqli_select_db( $conn, 'temp' );
      R3 _' t( v( A# A9 Y
  25. & A7 s. ~( f) h+ O% V9 A
  26.     # php中的文件锁
    , m, R, U% n& z) [- M$ V
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    % O" L* H1 ]/ G6 ~& o! K
  28.     flock($fp, LOCK_EX);// 排他锁 % K5 }! J2 y  g; V" |

  29. ; n8 L3 `7 u. s5 e+ ^( M
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    $ g. \# U+ q8 N4 F1 D5 v" i
  31.     while($row = mysqli_fetch_assoc($retval))* I# b) {6 z. S* \. w
  32.     {
    6 g% K$ X: p' o* ^( }
  33.         $id =  $row['id'];- I0 g( E3 L* q5 D  Z; A
  34.     }
    $ M, o; ^/ Q& B. b! Y7 T
  35.     ) E1 _  \5 p' f& O( c+ E8 H
  36.     if($id > 0)
    4 b! U2 h2 V/ z* ]' F+ R. n
  37.     { $ m6 V9 Z5 \' e; P
  38.         --$id;
    # W* y% _* U0 f% C
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    / ~/ [' l4 ]; x3 {
  40.     }
    : k# B- K' X, j) ~, |/ j
  41.     # php的文件锁,释放锁
    $ i+ C; g3 X1 }( G4 ]% u$ |9 _
  42.     flock($fp, LOCK_UN); 5 r& D8 P: y* D( ]* g, h' ?$ g
  43.     fclose($fp);
    , U6 {% g8 H5 F0 r

  44. " A9 R- u8 x5 C# z/ g' U
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    * G5 }7 U+ g7 Y( c! y0 V
  46.     // while($row = mysqli_fetch_assoc($res))
    $ Y, J. l6 H: n4 B
  47.     // {; W* n* a3 _% R! |* n6 d0 V( R: P
  48.     //     $id = $row['id'];
    + `7 x! D% C3 |7 L# X! D- t* Z. j
  49.     // }1 g# Y- s. r8 y
  50.     // echo $id;
复制代码
" ?6 @9 o+ T+ |9 |! E8 Y7 I, _
0 D3 B( U5 l* x( K2 t8 s" l
抢券活动实例:
  1. public function envelopeSnatching(){, o0 F0 d& k7 f: _5 g
  2.         $lingqu = $_POST['type'];
    6 C% m1 s$ \+ \. ]3 f
  3.         $uid=session('u_id');//用户id
    - i" Z2 s" ?$ `$ k2 A' x
  4.         if(!$uid){
    $ X* [; L9 P4 x. i1 e
  5.             $data['msg']='您没登录,请先登录!';4 b$ L  H$ A0 K: N
  6.         }else if(date('Y-m-d') != '2017-12-12'){( r2 t" A; Z+ X# s
  7.             $data['msg']='不在活动时间内!';' x6 C. @4 w& s  R! z- b8 Q8 }
  8.         }else{
    & ~6 t$ y7 N8 }
  9.             $hours=date('H');//当前小时数1 x$ z) N, F) y7 ?4 q
  10.             if($hours > '09' || $hours > '17'){; h0 g! ^9 S1 `2 ^! l
  11. & Y$ u1 z" w0 j& a1 d9 i& {
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的0 p- J3 w: C6 V2 a: g3 K
  13.                     if($lingqu == 1){
    ' W; _! W7 v8 Z) q& m
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过# y7 `* q- i# M4 M5 M
  15.                         if($hours > '09'){5 ^; m! r; q  J6 y- h
  16.                             $num=mt_rand(25,28);//优惠券金额
      P! ~) [& X1 e
  17.                             $id=1;9 t& P4 y5 P  z! b" |; K7 H
  18.                         }4 D) o# B* F3 s# _, e4 [
  19.                     }else if($lingqu == 2){
    ( p% D( b; |! g& ]- G6 K+ ~* o& f( Z
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
      Q5 O1 K/ A" s2 V- c  Z* H
  21.                         if($hours > '17'){! ?1 ~8 Q! B9 Y: H) P
  22.                             $num=mt_rand(50,55);//优惠券金额6 b( F9 I, M, p9 v8 O
  23.                             $id=2;) @+ b% ~) G" q+ F' L2 K
  24.                         }# z" ~- g8 T0 i8 Q* q3 J3 e
  25.                     }8 o7 X) [5 G& F) f, d
  26.                     if(!$id){% ?0 e! D' ~2 j3 v
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    $ k+ {( d6 T0 b4 t9 h  B) u
  28.                     }else{0 i3 B, z' O9 U' _9 W4 W
  29.                         if($is_lingqu){
    : p" R$ g$ Y  n5 S2 e
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';' ^$ J  ?: N' A# |
  31.                         }else{
    0 R$ p$ V7 K) G& R, b3 p
  32.                             //锁表) K$ b% J5 Q  a, z9 s
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    ; f! g) E! h0 t- @
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();) `3 @4 _3 V3 [
  35.                             if($active > 0){
    ; f. c  Y/ ~" E" g; W9 o5 j" G
  36.                                 //开启事务
    5 B5 M1 T: M$ g4 a4 }
  37.                                 M()->execute('start transaction');
    3 W/ }. j0 \* X' x$ H" r
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));. e4 ?! G! L( m4 t) d! D
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));0 Z" S$ W+ J0 ~1 ]8 G4 u4 x. J6 _* S
  40.                                 $members_preferential    =    M('members_preferential');
    2 }  U6 \- B+ Z$ s6 K9 q9 ?
  41.                                 //对应投资金额,/ k$ @! j& H, r% ?; S% h
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    6 O! h4 L* g5 }  }$ w
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');3 @( `2 l+ e' ^. N0 d' h5 @; `
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间1 f. ?- f0 }6 \0 F& B
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ! U5 L" J9 O2 n6 l8 \
  46.                                 if($save && $add && $add2){# ?- a) D, q* |, g2 h* L: i
  47.                                     //事务提交
    " i" h3 q2 U7 O5 Q( {  C
  48.                                     M()->execute('commit');
    ( s; ?: z5 J1 f
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    3 C( h# O( k' o* J5 J+ U  E
  50.                                 }else{
    * G3 C7 T& ?. G5 ~9 t/ \
  51.                                     //回滚
    + j8 i# B# {8 M2 y# c
  52.                                     M()->execute('rollback');
    ) d0 E- m! A9 U2 E
  53.                                     $data['msg']='未知错误!';
    2 o4 O2 I# T0 G4 G; T
  54.                                 }
    ! d2 i: K( _8 a& X# x
  55.                             }else{
    $ z. k/ ?, P) C8 P3 {
  56.                                 $data['msg']='红包已领完,你来晚了!';
    5 p6 f. d( ?3 x9 r" X* ^/ x
  57.                             }
    6 O, t0 c$ j5 E; U+ [  }4 f
  58.                             M()->execute('UNLOCK TABLES');2 p' F  H; ?8 h; G7 \& O* u' Z5 o+ P
  59.                         }7 y$ V4 o3 W0 t$ v: d' \/ v
  60.                     }
    7 ~2 K, l  V3 \9 ~) D
  61.                 }else{
    3 W/ u+ Y) E; ]( e. S
  62.                     $data['msg']='非法操作!';2 |2 S* P- O, n, V- T
  63.                 }) i7 f. m, N2 S9 {0 O) N+ `4 x7 b
  64.             }else{" o  g! }2 }; U" P+ x* k
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
      X6 ^/ z: Z8 U& H9 w1 T' R
  66.             }
    7 `0 d, D$ P9 K6 j6 j( B" E! [
  67.         }; e' k: w% x: S; y( D
  68.         exit(json_encode($data));
      g( U- D/ T# Q1 T" P
  69.     }
复制代码
3 p+ m# D; i! D4 f

+ w# U' M9 l7 Z% G
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:26 , Processed in 0.088065 second(s), 23 queries .

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