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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

! c$ Z: F4 @% M$ E* }5 G- T
Mysql中的锁语法:
! q" b7 m8 O% r2 M4 }$ bLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】2 x1 w5 `' X4 L
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表" ]# m) j& p/ O7 W
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
2 P: {7 Y( a1 v" {8 ~8 g! C/ |  }注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :; }6 n1 L/ F% R0 q6 G
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
' [( R. S. x; P/ K测试时,有个文件就行,叫什么名无所谓
总结:
3 M" v8 x/ k. |& P2 v5 t5 A项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:9 A* X$ M8 o9 c* o& S( r5 S
1. 高并发下单时,减库存量时要加锁
) N: V+ ]& ?5 n- O' a7 `7 L9 O6 N: m0 L2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    ! ?3 J6 \3 ?% J9 @% j$ R7 t' K
  2.     模拟秒杀活动-- 商品100件  k# [& u+ J/ d; P$ a
  3.     CREATE TABLE ta
    / p. T1 M) R  @8 ~: t7 c7 m: i- N7 B* G
  4.     (
    - m, |2 q* A$ R! b/ m' a1 k& P
  5.         id int comment '模拟100件活动商品的数量'
    % u+ _( U0 T9 Q' k4 I( d
  6.     );  E, `1 J4 G3 B
  7.     INSERT INTO ta VALUES(100);2 \7 v' f. }9 X0 ]% ]/ ?
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件' F. N( e; F) t5 E
  9.      */
    / t# g" b, @9 G
  10.    
    , {- o6 Y3 H% _9 I% q) A. C2 B6 r
  11.     // 关闭错误报告' V0 I/ ]# k3 ]. h6 i4 S
  12.      error_reporting(0); 0 b" N' J1 Z  o0 a( x3 Q

  13. + d1 ], J5 o0 x$ U5 `
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    # _1 N8 l3 Y$ I/ K7 A0 U3 m) P
  15.     $dbuser = 'root';            // mysql用户名* h2 t- c# {- f5 R0 v4 ?* M/ D
  16.     $dbpass = 'root';          // mysql用户名密码) g. Q, \5 V; W0 v
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    / M6 q& w/ d- I7 C7 F: `' l
  18.     if(! $conn )4 y& O  C  N, R  n/ j
  19.     {
    : J  g% x( c6 M  V+ {' |: L2 a
  20.         die('连接失败: ' . mysqli_error($conn));) |# A  `9 x3 w# ^3 ~6 S
  21.     }6 v7 p0 V2 j3 E' @3 u' W
  22.     // 设置编码,防止中文乱码
    5 l0 O/ l$ r, ~* p
  23.     mysqli_query($conn , "set names utf8");' Y; p, w7 v$ Z. m
  24.     mysqli_select_db( $conn, 'temp' );
    ; o' ?  D7 a# q( H; I

  25. . R6 G, [/ u. X! q
  26.     # mysql 锁 3 v; e/ R* `3 F7 I2 V, {. \
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    $ w2 h5 A4 M) Z: D
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); ) i, ^8 B) X- y3 @
  29.     $id = mysqli_result($rs, 0, 0); 5 e; h# p9 F1 j
  30.     if($id > 0)
    6 _% ?- S+ \2 X6 V) _
  31.     { ; P$ |+ q* `' ^
  32.         --$id; 5 I/ D6 M) i: V, E6 \4 C5 w
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    ' ?7 u1 {& X+ d! ^3 x
  34.     } " y5 I; E7 H. g

  35. 0 H# K, G: j3 U* k
  36.     # mysql 解锁
    ; ~) ]: D5 g* ?3 w  d& D5 B& O$ o
  37.     mysqli_query($conn , 'UNLOCK TABLES');& C" w! s3 A: z6 T: t
  38.     //查询解锁后的id值* ^* o3 T* v7 {
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    " H6 M4 [3 c7 _% N* d# w. ?
  40.     // while($row = mysqli_fetch_assoc($res))
      T2 p+ J& E7 [$ }" }; ?# i
  41.     // {
    ; q* ]3 f/ J( Y; x9 S0 S$ B
  42.     //     $id = $row['id'];
    $ ]: j- m) j- ]
  43.     // }- D6 H! c' o7 M  z; ^& X
  44.     // echo $id;
复制代码
0 k1 W6 @6 g) a  b2 ~
) P6 s3 C; Z' q. z

5 k+ b$ g. Z% Y
PHP文件锁示例:
  1. /*' T# ]8 G+ S3 }5 Z. V& J
  2.     模拟秒杀活动-- 商品100件% u3 d4 @; z! N6 M4 }/ C4 p
  3.     CREATE TABLE ta
    , ^  h- D, V' Q# D9 j
  4.     (
    6 h/ ]7 T, t$ [+ n
  5.         id int comment '模拟100件活动商品的数量'
    ' v1 L, }! ^, h3 G0 L  I
  6.     );" l; m3 l' s, S; R" Q. j
  7.     INSERT INTO ta VALUES(100);4 n$ |+ \+ _4 m# r' ^
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件4 _5 @9 N/ V: H3 d( e
  9.      */
    1 K1 `/ }7 p6 V3 d
  10.    
    + a7 J5 A( q& R6 t  u- O+ V. r
  11.     // 关闭错误报告
    2 M' |  T  A% W; x) e# r. W9 @
  12.      error_reporting(0);
    7 j* d: f0 ^+ R  ~+ o; H

  13. 1 N2 q! P, ]; a) e. \  E0 Q
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址5 ~/ {7 o* k- ^( V# O7 w) g, {
  15.     $dbuser = 'root';            // mysql用户名
    : V+ j1 k$ m9 n0 P0 z
  16.     $dbpass = 'root';          // mysql用户名密码
      j1 l6 ]2 i( b
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    & v% L  }* D8 F) {8 m
  18.     if(! $conn )  [: Q2 g% z, \( y; g1 j
  19.     {% y+ z! c- m6 l
  20.         die('连接失败: ' . mysqli_error($conn));
    $ Z! P! T; z1 H' e
  21.     }
    6 @+ n; i& j9 I) Y1 W
  22.     // 设置编码,防止中文乱码7 A4 C) b1 @7 e% j
  23.     mysqli_query($conn , "set names utf8");' g/ |* u: L" h1 e$ ~5 O" @: [
  24.     mysqli_select_db( $conn, 'temp' ); $ `, K/ f3 m+ [- H- A

  25. 7 o; l: n- g( _# ]: B
  26.     # php中的文件锁 ! l- C3 C/ {9 ~9 d
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 9 j/ c5 U, o' A. {: y
  28.     flock($fp, LOCK_EX);// 排他锁
    ) G8 D& @- a+ W( G3 v, v& P( |
  29. 6 [" o( Q6 x9 w  {! D
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ( c& j5 y' r7 o# d# E
  31.     while($row = mysqli_fetch_assoc($retval))  }  A) U9 T- [; d+ V4 E; h
  32.     {
    % `; Z  v0 _, ]# ?
  33.         $id =  $row['id'];
    , F. j' g. o0 X- p( I
  34.     }! I0 ]6 G0 l! s8 ^2 T  B) g& J
  35.     + X. L/ r/ U5 u* k
  36.     if($id > 0) 7 j8 F( Q( `) R& x) s+ y( U5 H( e
  37.     { 4 D6 c8 Z8 @, J9 s3 @1 {: Z
  38.         --$id; - q. e6 a* n( i- E- F" b
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    9 W& D& J' D7 S; F  j) v
  40.     } 2 I$ k$ w" Z7 ?# a0 @; `3 ^) t
  41.     # php的文件锁,释放锁 6 q9 p3 b, F; J  _+ `# V
  42.     flock($fp, LOCK_UN);
    0 f5 [, m& J5 e( ^
  43.     fclose($fp);/ ]) X8 I( k4 W, R# K4 @+ m

  44. 5 x4 X( o- M3 m4 {7 ~: a0 Y% \
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');, Y; n9 ~. E# s, {
  46.     // while($row = mysqli_fetch_assoc($res))
    & O$ m( e( @' u1 ~. o
  47.     // {
    : ^' |# c' t6 t
  48.     //     $id = $row['id'];4 s5 T/ _  d$ o" P3 A
  49.     // }3 C8 j/ w% u3 b5 d
  50.     // echo $id;
复制代码

6 ?" Y( {  S, n0 ?" q0 a; o8 Q  ]
2 J: V8 N2 ~3 e) k
抢券活动实例:
  1. public function envelopeSnatching(){
    $ w! r. A+ v, o; z1 E( j! b9 ~. w
  2.         $lingqu = $_POST['type'];* p2 s+ L4 `) }: s: t: n
  3.         $uid=session('u_id');//用户id
    # j5 \$ X" ^1 {; V$ ^$ {; O' }
  4.         if(!$uid){' t  T# g4 G  X  i% v' g
  5.             $data['msg']='您没登录,请先登录!';/ G. Z2 Q+ u+ _
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    ) c- W1 C0 o* q' ~8 n
  7.             $data['msg']='不在活动时间内!';2 H, [% _1 C  V+ p: U" x& r+ m
  8.         }else{
    , M7 h" i3 i% G6 Q& q) H" q5 D' R3 `
  9.             $hours=date('H');//当前小时数
    3 L. A& b1 A- O1 k) `
  10.             if($hours > '09' || $hours > '17'){
    ) Z$ m  X# p* G. a
  11. : P, K" o5 d! r" h5 M1 g! i
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    3 n* q1 ?- O% N! k" P1 P, q
  13.                     if($lingqu == 1){
    ! Q: ?. U# ~' E
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过7 W3 D# I" I- R8 b) h' i! i
  15.                         if($hours > '09'){1 @+ A+ P' V" H# U1 C( d7 N* b+ }' R
  16.                             $num=mt_rand(25,28);//优惠券金额1 e5 \9 g: b- v3 {" N0 h
  17.                             $id=1;) e3 s9 A# a9 ^5 w1 W+ G
  18.                         }/ M8 ~! s) c1 \. J1 S* W
  19.                     }else if($lingqu == 2){
    8 w% u1 C$ Z) C3 ~5 Q
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();1 d, X6 ^5 w0 s0 o5 Q1 S1 u
  21.                         if($hours > '17'){
    2 M0 A9 \3 T& W' P% j( q
  22.                             $num=mt_rand(50,55);//优惠券金额5 ~: f9 R% m9 Y
  23.                             $id=2;& y# S. k9 \% j" q/ z. B5 L3 N
  24.                         }  Z3 W4 o1 _9 Q+ h, L7 N5 a
  25.                     }9 N- C2 }$ N0 k7 Q
  26.                     if(!$id){/ ~8 R7 @( c+ q* a6 |
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    0 j$ a, V/ }% ~7 j; x  i% C
  28.                     }else{
    5 Z' w* n- s+ y% e* f
  29.                         if($is_lingqu){
    $ E+ W" @% B; i9 ^
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    . J0 v: g( @8 t
  31.                         }else{2 r) g7 R" I; n4 `* L$ n
  32.                             //锁表
    ) _" e. S2 j" f; O/ o3 \- c' a
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    8 v6 j  C  y4 b/ `3 Y
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    / k; L9 d- k$ `+ {; x$ P; y
  35.                             if($active > 0){
    - U3 x4 D$ r1 J
  36.                                 //开启事务
    2 H7 w& g9 k  E$ H2 l) L9 ?; {
  37.                                 M()->execute('start transaction');% M. m1 ?2 P! s# Y4 k
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));% D8 X  z$ `# Z6 E
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));& y0 y) d+ i; S9 H: s
  40.                                 $members_preferential    =    M('members_preferential');* Y5 K0 y3 s( Q* B% y& T, f; V
  41.                                 //对应投资金额,1 q" p; Q! w7 I/ D( ~$ N
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));. r1 [8 k3 N1 N  V$ R, }  }
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');; [$ x; w4 s9 I* Y' Q1 E  q
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
      a! p" W4 {, \& @6 u) t) K
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券; s2 G5 B, ~$ B
  46.                                 if($save && $add && $add2){
    % T& u. d8 m- e. Y& c
  47.                                     //事务提交
    3 c- k) O! s& g0 B% u: N5 S6 r$ T8 P& w7 z
  48.                                     M()->execute('commit');& S  a5 Z2 M) r" g8 T
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';0 p5 s4 V# C, [! P! d( A
  50.                                 }else{6 o8 {6 @& ?9 Q2 }
  51.                                     //回滚3 ]1 F1 P% p' y8 L
  52.                                     M()->execute('rollback');
    ; f- T8 y( \" f6 r1 w( [7 r
  53.                                     $data['msg']='未知错误!';
    0 P' O2 R: ~& Z* R8 F% a( v0 Y
  54.                                 }" C  O2 b  n4 E5 q' ~* I! g
  55.                             }else{0 p2 B: A* T4 E+ Z0 f2 w
  56.                                 $data['msg']='红包已领完,你来晚了!';2 b7 P7 Q$ A- q$ T8 ?. w9 w
  57.                             }# [* `* W* j' e+ P; r$ y3 S
  58.                             M()->execute('UNLOCK TABLES');
    9 C* T# t$ |% i. i4 u) ?& o
  59.                         }
    & `, g/ f  q; X9 i/ X+ o
  60.                     }, g4 o3 Z. Z' @: F/ g
  61.                 }else{- P7 s7 E1 ^8 y' n+ Q
  62.                     $data['msg']='非法操作!';
    , Q! u" B. F1 o& X: F4 h, T+ ?  m2 a# O+ Q
  63.                 }
    ) N. U7 V4 z. Q8 T/ Y. Q
  64.             }else{1 Z2 b5 u- |% f; z6 Y8 W
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';9 J9 t4 S& M- m4 `. d' F
  66.             }
    ! o# w4 q1 B2 [0 a8 A1 y
  67.         }
    ( S0 R6 m6 Y$ @7 ]5 r% p2 ~
  68.         exit(json_encode($data));
    0 K: S. Z. C. k- c* `7 n. O
  69.     }
复制代码

( `5 {6 p9 K5 z8 ]+ ]. z) g3 }% G% A- |2 p0 d4 V# m, t4 A- `
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-3 15:28 , Processed in 0.129675 second(s), 21 queries .

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