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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8209|回复: 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://请求的脚本
复制代码
% {3 r0 u8 c/ X+ H* M
Mysql中的锁语法:
4 c( N8 k- O( E* ~( nLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
1 G  l, f# P3 s8 z- h5 KUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表7 i1 h2 ^0 B& R9 [+ p6 @$ ~. h% ~$ Q
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞$ E# Y# W3 r: V1 G' Y% Z. z
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :0 n1 ^4 n8 Q$ w: A3 ~/ L  f
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。  D; M5 V* V- z
测试时,有个文件就行,叫什么名无所谓
总结:9 _4 v$ ]/ T3 L9 ~- e
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
( ^  w2 I6 j5 o" n1. 高并发下单时,减库存量时要加锁
2 F: `* {$ a5 u2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    1 U7 J0 s& j7 t1 E
  2.     模拟秒杀活动-- 商品100件& L9 |. {" c$ ^9 v) j1 o  D
  3.     CREATE TABLE ta" U9 w1 H( p, }/ ~, P# d5 v
  4.     (5 D" m6 t3 H: |
  5.         id int comment '模拟100件活动商品的数量'
      q% h6 v7 _4 Y9 b6 u
  6.     );
    5 ?' c7 Y" [! Y/ J8 p9 n
  7.     INSERT INTO ta VALUES(100);
    1 j" @7 B" [9 a2 K8 p
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ( }  l" w4 r, c2 h2 e) P- h
  9.      */
    ' I3 {  k& G. B1 @* f( ^+ }0 z$ b
  10.     - B' y$ D  i8 e6 q! S
  11.     // 关闭错误报告3 ]4 O3 m3 ^4 _* o3 G
  12.      error_reporting(0);
    * `# q( m8 T: e& ^3 D7 H
  13. ) k4 Z1 v+ o& y$ F! d7 s% V
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址# \+ R3 \- e; T) D3 x
  15.     $dbuser = 'root';            // mysql用户名5 `) O/ |' \+ o$ v. A
  16.     $dbpass = 'root';          // mysql用户名密码
    2 V; D( B. J5 u- `9 n
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    1 G# y9 o2 e" C5 S' m# W
  18.     if(! $conn ), ~- M0 D" p1 b! s" W
  19.     {
    9 e* Y3 \$ I" s5 V1 ^; G+ Z
  20.         die('连接失败: ' . mysqli_error($conn));& I9 @3 q: {# F1 T$ W4 B0 |, {
  21.     }
    . W, f% I" }. _. |% W
  22.     // 设置编码,防止中文乱码, N6 Z! ?4 c# U# `2 I/ P  Q. e
  23.     mysqli_query($conn , "set names utf8");
    4 ]$ q0 U4 D2 Q, U
  24.     mysqli_select_db( $conn, 'temp' ); - C, ?; j  H7 P* K; q8 u+ r
  25. # e. h) w9 f" L- n8 F3 E7 d. R
  26.     # mysql 锁
    ( ?+ h+ J" x  F8 ]" D/ V' {
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    " U* B. p3 G5 L# f% d( m
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    2 X% C7 b" V4 I; o# X
  29.     $id = mysqli_result($rs, 0, 0);
    + p# z4 ~; n- ?- D/ |! f4 l
  30.     if($id > 0)
    6 E0 q, c5 Y$ k
  31.     { 0 u$ t# x2 `! U" g/ y* i5 N. {
  32.         --$id;
    ! f' N9 i# _1 k- I7 F9 s  g
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    ' ~1 e# j+ r( r6 a
  34.     }
    $ s8 r6 c  ?8 L5 S# k- w* K" l8 R
  35. : D# Y- v3 p; x  D# s# b
  36.     # mysql 解锁 , D+ `9 x: q. Y
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    / a: V/ D& \6 E0 @! a, J7 E- Q- Z1 F
  38.     //查询解锁后的id值) \' I+ d1 ]% `) Q" y! O5 _2 T
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
      {$ N# Y) c/ q* V& X/ [2 f
  40.     // while($row = mysqli_fetch_assoc($res))
    % w* m" Z% h% n% d
  41.     // {4 i- m3 ~4 @$ Z5 [% A8 \
  42.     //     $id = $row['id'];
    0 d$ h% z1 t. |/ k
  43.     // }5 c! I; N! D* ~& Y9 m/ o+ C9 P
  44.     // echo $id;
复制代码
, m$ S' S9 J# T3 k
3 K* X: c& J! ]; s/ j

9 @  ]6 V4 @" i
PHP文件锁示例:
  1. /*" q# Y5 [% d( @8 g2 f0 \
  2.     模拟秒杀活动-- 商品100件& f( y. I) _' p+ P+ l9 G
  3.     CREATE TABLE ta
    + l0 ~' A* {1 Y& E
  4.     (+ q! S5 g* P# k: Z) {. x4 z
  5.         id int comment '模拟100件活动商品的数量'
    " N7 V3 P+ l1 _* x
  6.     );9 l" d+ `0 G2 Q) K
  7.     INSERT INTO ta VALUES(100);; O. J6 i: K& A5 [
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件2 U/ @7 ]4 w, w. V& ?  t- V, o
  9.      */ : N0 D" A6 y; O. F4 Z
  10.     " W$ A; t2 h, z, g& a4 y
  11.     // 关闭错误报告
    8 T8 G, x9 R: w8 j) C9 e" D" d
  12.      error_reporting(0); # {5 z0 S% }/ Y; U3 e& }9 B: w# O

  13. 3 N( w+ K) J1 O0 v$ g
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址1 F9 q# z1 F- s: U$ Z# ~2 L
  15.     $dbuser = 'root';            // mysql用户名
    1 q: i9 e. ^  K% U7 z& u- u+ F& s8 h
  16.     $dbpass = 'root';          // mysql用户名密码7 d1 K$ i; k& o- B) W
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);5 X; d- N- k/ y: O7 W' D$ D
  18.     if(! $conn )2 d6 l. I7 P0 r$ T5 f
  19.     {
    & O* K9 }2 J2 p
  20.         die('连接失败: ' . mysqli_error($conn));* P5 w& k2 @2 ]. L1 e
  21.     }( f6 }; R! G8 X+ g9 [5 E* U' [
  22.     // 设置编码,防止中文乱码
    ) w) T) T+ `- ?8 L( x
  23.     mysqli_query($conn , "set names utf8");
    : H; v) V! J( h
  24.     mysqli_select_db( $conn, 'temp' ); 9 b: R2 d! z' Z/ `6 \) e

  25. 3 v) x  |6 L9 X7 K1 k
  26.     # php中的文件锁
    & R1 J% \4 ^! s$ ^
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 # p/ X: M" ?: d5 a
  28.     flock($fp, LOCK_EX);// 排他锁
    - |1 k0 M- A0 v9 b
  29. / u, f* V$ O6 P6 m& b8 s' F
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    ) M8 x7 Y% ?$ A" U8 j  v7 A( B
  31.     while($row = mysqli_fetch_assoc($retval))+ y$ e  X! [. L6 p& n
  32.     {
    ' i" D5 \1 C6 n: }
  33.         $id =  $row['id'];
    1 `5 j& F4 V6 v9 L
  34.     }9 t9 J7 u5 J) j; a4 |' T3 G
  35.    
    3 M* \/ `* W! ~! d% ?8 l
  36.     if($id > 0)
    8 q1 E  P6 N6 E
  37.     {
    9 {8 B6 W2 _7 x
  38.         --$id; 6 q& G3 N8 V, e& j5 T) y. P4 U
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); # ?$ r+ i% @) w# U. }' |% z
  40.     } 0 e6 @9 C2 B/ |# y' c* [% \+ G
  41.     # php的文件锁,释放锁 : m: K9 v% E  V& W$ d4 E& X
  42.     flock($fp, LOCK_UN); - F4 t: m5 K/ [# _  p( }
  43.     fclose($fp);/ o) h5 v/ [+ o

  44. + p. x: F' @; x
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    . z- ]3 {7 w, m, V
  46.     // while($row = mysqli_fetch_assoc($res))8 ~: F5 c: m9 ^
  47.     // {
    ) C2 T- q1 E; m/ g2 f; j9 y
  48.     //     $id = $row['id'];( {' Y+ b$ N1 r) H
  49.     // }
    $ `) ~+ ]' {/ H6 P- T+ L  l
  50.     // echo $id;
复制代码

2 l5 k  ?. W- ]* T' T' I" v( F/ W$ T0 |% R; u6 m
抢券活动实例:
  1. public function envelopeSnatching(){
    6 M& K6 V( U# W8 V. y( h
  2.         $lingqu = $_POST['type'];
    . N: d- p! i- }; C
  3.         $uid=session('u_id');//用户id
    5 ], @7 ^& I4 Q; G% c  g$ r
  4.         if(!$uid){
    1 a# y  @8 n1 k" C) J' e
  5.             $data['msg']='您没登录,请先登录!';
    ( S4 @" S0 z% ^) Q7 ~- b# M, ?! Q
  6.         }else if(date('Y-m-d') != '2017-12-12'){5 H* I- L+ U3 x' o
  7.             $data['msg']='不在活动时间内!';
    " [! o0 }# _# P$ h. Y
  8.         }else{# J/ D6 Q# b: K) e2 P
  9.             $hours=date('H');//当前小时数
    0 n* a7 ]8 m* ~7 Y- ~
  10.             if($hours > '09' || $hours > '17'){0 ^2 ~9 m+ b$ o8 ?# _( p

  11. 9 ?9 H  b( i3 B
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的' ~; w# i8 C$ D  t& g8 f9 n: l
  13.                     if($lingqu == 1){2 ^4 K. |- }; n2 J+ V6 A; U! @
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    1 J  Z1 X. R' K2 {, n
  15.                         if($hours > '09'){
      n4 m/ ^  L7 G. j: o4 b1 m& Y
  16.                             $num=mt_rand(25,28);//优惠券金额
    5 T7 u; w) L& b/ s0 A' X% q+ b
  17.                             $id=1;6 ~( l3 `4 N- l& D( `
  18.                         }
    $ b7 Y) }3 J0 y# k+ J3 K! S
  19.                     }else if($lingqu == 2){: W' M% R5 O2 C; D7 j5 {  J
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();7 _0 e9 n% N1 L) h  w
  21.                         if($hours > '17'){
    ( r4 X! u+ U- N9 Z# k' g5 c
  22.                             $num=mt_rand(50,55);//优惠券金额
    ) f: H3 G. L3 v9 Z9 u
  23.                             $id=2;
    7 @2 J! u7 a. \& W
  24.                         }
    - z6 z* M4 Z1 b( ]/ ?4 t, M
  25.                     }
    , L. o9 x3 b: t' m7 l
  26.                     if(!$id){
    $ ~1 V0 @( z" }+ @$ d
  27.                         $data['msg']='时间还没到,晚点再来吧。';4 u' J- a% q  j  h) X
  28.                     }else{
    8 u; i- s" K5 o) L4 l& G$ h
  29.                         if($is_lingqu){7 E, X6 Y) g" X8 U
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';. M' L9 V6 I2 T; `0 u% ?
  31.                         }else{1 f% D; ?$ ^$ l. |
  32.                             //锁表) u! |# I1 |. h  X4 N. }1 l& v
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');8 V; ?: W7 a! F3 s
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    - M+ u% M0 u3 z% t3 j) ?7 a
  35.                             if($active > 0){/ ^: c2 P7 L/ n9 n
  36.                                 //开启事务2 A3 n, f$ e7 X# @. N  h
  37.                                 M()->execute('start transaction');
    4 v2 H' ]3 K5 k" [/ T
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));1 l+ y7 ^- A8 k7 R. t
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));. @: g1 X0 _! c4 }" T, z
  40.                                 $members_preferential    =    M('members_preferential');" V7 L3 B9 h/ A/ k+ W
  41.                                 //对应投资金额,7 R4 {- q- S: a# f0 P/ N
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));9 k! W4 W' |& H0 k
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    , N  X8 ~3 i+ K' S& q& H; _# k
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间) A! r7 _8 X* ~
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ( _- R# j4 [7 o8 b' b
  46.                                 if($save && $add && $add2){1 R. k: C4 k- y1 ]. h6 x' g: ?4 ~- l
  47.                                     //事务提交+ v( I7 t5 o3 c6 B: ]
  48.                                     M()->execute('commit');6 v8 I; ?- T2 h/ F
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';  V+ z  c4 J0 o* F) m3 w* o
  50.                                 }else{# n3 Q" P% Z1 B8 ?  X
  51.                                     //回滚8 [% v7 b+ P. f
  52.                                     M()->execute('rollback');
    % g3 s3 n0 \$ P
  53.                                     $data['msg']='未知错误!';
      O; F+ J4 S) m. {. Z
  54.                                 }5 b; p& h3 q0 n2 S
  55.                             }else{0 X; o! t% w9 H- i7 y3 r6 g; ~8 T
  56.                                 $data['msg']='红包已领完,你来晚了!';
    5 A$ ?. F4 n' ~6 B- d: U
  57.                             }+ F0 ], G4 \3 E7 J
  58.                             M()->execute('UNLOCK TABLES');
    # U% |5 F1 }. c. h; V- H
  59.                         }! l8 J& N% `' D* k9 R
  60.                     }
    ( S/ l! j" H# q  r2 U5 F
  61.                 }else{
    2 {: J# F9 Y. R
  62.                     $data['msg']='非法操作!';5 {( J+ p9 Q5 U
  63.                 }# ~7 q6 W2 E, r. K
  64.             }else{
      W5 k, s1 n8 r) U. v% w
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';; x( i0 ?& Z& H( ?: c5 m
  66.             }8 M4 J2 q" f8 r) o1 f; z3 C
  67.         }
    1 \6 e/ T0 A( J, @) x8 N
  68.         exit(json_encode($data));
    3 [8 [9 ^' [* Y5 ]6 L' T
  69.     }
复制代码
- b/ _, f1 g: S/ c
# h% K$ h! h2 Z  H2 z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 13:04 , Processed in 0.053627 second(s), 20 queries .

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