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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

1 _' L, Y. M  @
Mysql中的锁语法:( ~( G4 n% `" z9 h3 ~7 v: c3 R
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】% {7 I3 b2 W  {: [  N+ p& V
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
( I  j/ f" |( G2 GWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
: D: U- o  x3 M注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
8 c! ^+ ]/ \  n6 C7 }9 w9 L文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
: E2 l! T, _' Y4 `! v; N测试时,有个文件就行,叫什么名无所谓
总结:5 X: X) K" E- C/ q1 H- H
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
/ t( |5 H9 b# X. b: z% K1. 高并发下单时,减库存量时要加锁
5 l4 O& d6 J$ p6 ?/ e2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    & u  k) V3 C2 {: A$ R
  2.     模拟秒杀活动-- 商品100件1 h8 N5 ^' k5 e) y+ j
  3.     CREATE TABLE ta
    ; n4 A+ ?1 Y! k" p1 ?3 b
  4.     (0 s; s+ T# c# m; u+ a4 o
  5.         id int comment '模拟100件活动商品的数量'
    , w* E% M6 q0 r( P+ _) n$ B
  6.     );
      w9 Y, W" S1 O! m/ ^
  7.     INSERT INTO ta VALUES(100);
    ' E( }& O1 w& w1 p% z1 K( {
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    , y2 o. b, A* M& R7 Q
  9.      */ + ^2 E; I  U3 e$ x' |( n- ~
  10.    
    6 C3 Z, ^% q$ l8 l& K. G
  11.     // 关闭错误报告
    - ~0 S1 _* k) d6 N+ q- L6 W% x
  12.      error_reporting(0);
    : V8 L# t8 x+ g0 d5 B

  13. 8 S3 n  V  C- L6 J" @5 _  T: g
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ; ?! y, f, ?' {: N' v3 S. R! B7 |
  15.     $dbuser = 'root';            // mysql用户名
    % l2 g8 d4 u4 S$ Q: V7 k& [3 X
  16.     $dbpass = 'root';          // mysql用户名密码. X) K, u& t$ p6 {
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);& b( @4 Y% ^$ k$ b9 t+ L1 ~
  18.     if(! $conn )2 n+ o" k3 ?' l+ H3 D# ]9 y
  19.     {* b- C5 t0 I6 K8 S$ W
  20.         die('连接失败: ' . mysqli_error($conn));
    ; d: @- D. l% }( C; M9 ?
  21.     }
    2 M8 @4 W0 ]# H$ t, D! c
  22.     // 设置编码,防止中文乱码$ I4 m1 l) B: J: r0 m* F) r6 P
  23.     mysqli_query($conn , "set names utf8");
    & C+ V. Z7 H* h. h) k
  24.     mysqli_select_db( $conn, 'temp' ); 1 T( F" ^- |( `% W9 }/ Y6 Q
  25. 7 E. g. Z3 I* t" b1 V
  26.     # mysql 锁 6 g6 Z! e) n9 J  B1 B, r- `$ ]
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 / k6 g% h7 L; d1 [
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 3 N+ l  k- C  c  O! j. `2 a
  29.     $id = mysqli_result($rs, 0, 0);
    & c" C  M. e* A: Y
  30.     if($id > 0)
    & ?. v" _) y7 X) m. \/ a
  31.     { 5 M1 ^' H' \4 X2 F" I
  32.         --$id; 7 \, ~1 X7 n1 y& K2 X; b
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    ( z0 F9 `# ^8 k& x/ n
  34.     } . i5 x; k' r! H0 w

  35. / M# U$ y' b* H2 q  \
  36.     # mysql 解锁
    ' D  e9 v& z' F
  37.     mysqli_query($conn , 'UNLOCK TABLES');8 ^) E3 ]3 J# v& E- d/ W
  38.     //查询解锁后的id值
    7 t$ d* E8 p$ ~6 w9 z- h/ U
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    9 i$ e' p! O3 k+ X
  40.     // while($row = mysqli_fetch_assoc($res))% Y' a! T3 `7 \9 |3 _* Q
  41.     // {8 V; b) u. n& H7 d
  42.     //     $id = $row['id'];
    0 U  O1 E! G9 i  c3 W5 [4 b. Z* r
  43.     // }  P+ _! L' x( r; w+ k3 l
  44.     // echo $id;
复制代码

( \5 Q6 ]# I9 y+ a" Y) D3 x7 i  t4 X6 h# W; o4 j5 r$ E# T* F/ k

) \( v: q& ]( o" g
PHP文件锁示例:
  1. /*9 Y( g  h/ A; K, w
  2.     模拟秒杀活动-- 商品100件7 b4 x; t, h( T6 c+ z. B" b1 [( N  ^
  3.     CREATE TABLE ta
    4 v) r: h$ n4 |; Q0 X5 c
  4.     (
    ; W7 y; I1 n. C
  5.         id int comment '模拟100件活动商品的数量'9 u6 f  G; F' y  c- u
  6.     );8 [) z7 M$ P% E/ w4 n6 I
  7.     INSERT INTO ta VALUES(100);: [( A. B0 n6 o1 E  U; O. }
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件# a- q% u, L1 q. s
  9.      */
    ; P; M6 Y  N  C! f3 N
  10.     - K0 Q1 L% I- a& r$ ]) n, f
  11.     // 关闭错误报告
    8 S* P9 E2 D3 c% c7 p3 i* ?
  12.      error_reporting(0);
    + A8 G- ~, B; s/ T) f

  13. 1 G, x) F; [6 C% Y) w
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址5 |2 F) M# ?4 a" F% g! s. e4 v3 M
  15.     $dbuser = 'root';            // mysql用户名
    " W7 G" M$ W  n; N+ S9 Z
  16.     $dbpass = 'root';          // mysql用户名密码6 M: E% r7 V! H6 b7 s2 P1 j) f
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    . W4 z, B9 Y  U& l4 r3 ^3 z
  18.     if(! $conn )# A0 z/ A; F' k) b0 _* s3 s! `
  19.     {- ]: K) Y. G! O* q
  20.         die('连接失败: ' . mysqli_error($conn));% h. [* B/ V; {+ L  x* K& h
  21.     }
    : D  S) M  r/ ^3 Y' V% V
  22.     // 设置编码,防止中文乱码/ T& D4 M4 ?6 q5 L3 b
  23.     mysqli_query($conn , "set names utf8");
    6 k* e3 S) v# _+ }' z  Y. W
  24.     mysqli_select_db( $conn, 'temp' ); 6 V! k& u& c  C  E) D
  25. 6 L% h. W9 ~, K3 K3 E: s
  26.     # php中的文件锁 5 s8 e6 U6 O  Y: E- C" L6 D, _: @
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    6 o5 q, x' T7 Z9 w8 a
  28.     flock($fp, LOCK_EX);// 排他锁 . _$ h! u' x$ H% S* _, O; C5 ^6 Q8 i
  29. " u" c  E, F% y% V1 }" Z, \
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); # N& e2 ?) N1 g& f  m. K" k
  31.     while($row = mysqli_fetch_assoc($retval))$ J7 f, ]0 U, n! U/ u( p
  32.     {
    ( }$ y# P, N/ }3 Y: ~
  33.         $id =  $row['id'];
    * H* ?5 Y/ }* c- M
  34.     }  o! d' T& R' ]! x
  35.    
      j, J+ ?+ ~( k$ ?
  36.     if($id > 0)
    8 `" O: y- {9 y1 K6 Q9 q; a) L' U
  37.     {
    * ]% ~: I+ I  E; Y, k  H, x
  38.         --$id;
    , k% e4 j4 U+ i( [
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 2 X1 d: [. T' X9 R2 ~
  40.     }
    + j' M/ t2 O7 n5 D5 P
  41.     # php的文件锁,释放锁
    : \' Q9 w0 e2 p9 t3 c
  42.     flock($fp, LOCK_UN); # t3 Z5 @# ]/ x3 Y6 G* y
  43.     fclose($fp);3 L3 E' k7 o3 |! x0 V

  44. & i# [5 x9 Q8 ]$ S! @: \% J
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');/ k# s& t( j' l8 N; W
  46.     // while($row = mysqli_fetch_assoc($res))( I+ x! ?8 Q1 J0 P/ `& i2 ?7 L
  47.     // {5 U- d4 L& S7 @
  48.     //     $id = $row['id'];
    0 {8 r- {; p$ }, g5 A
  49.     // }
    . S$ ]8 r' a- u9 f; C' K: B) u% p
  50.     // echo $id;
复制代码

0 w$ H) Q; }; X3 b3 Q8 N6 M7 D; n( G
抢券活动实例:
  1. public function envelopeSnatching(){
    & j  L0 R0 P( y7 q3 e3 o: H
  2.         $lingqu = $_POST['type'];
    , Y3 J  H" L9 D$ {/ H
  3.         $uid=session('u_id');//用户id% c2 y9 b6 |6 A* j0 n% X4 O
  4.         if(!$uid){
    - ~5 k) c+ o- _) ]" p5 U( I
  5.             $data['msg']='您没登录,请先登录!';( m. d. v4 m) @0 ]' {
  6.         }else if(date('Y-m-d') != '2017-12-12'){' w& n& G$ ?3 h8 v* B
  7.             $data['msg']='不在活动时间内!';
    ( t% D9 l8 u4 @& |- L+ j
  8.         }else{
    / S+ [2 L. ]- N  G
  9.             $hours=date('H');//当前小时数
      `5 R* h( M4 O6 f; B7 p
  10.             if($hours > '09' || $hours > '17'){
    5 c8 U  H4 T2 f0 {$ U! W

  11. ' P6 ^6 Q, [/ Q6 o
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的6 X& g$ X7 ~; y, O$ L
  13.                     if($lingqu == 1){
    1 Y7 q: t; w: k3 o& U4 I
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过, F2 x& Z- M" P- Y% R' L/ S2 r% G
  15.                         if($hours > '09'){
    8 F; r0 }) E" Z" F
  16.                             $num=mt_rand(25,28);//优惠券金额
    ! o" a8 B7 y+ E. z  {
  17.                             $id=1;, E4 ]' u$ x: M
  18.                         }
    / @: M  I" R5 T1 w, f; X+ W9 v
  19.                     }else if($lingqu == 2){% E+ g/ n: l: U  A, e% u
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();. X+ p" b2 h! o0 T, u& a4 S
  21.                         if($hours > '17'){
    $ n9 j- C3 R0 w  p+ s
  22.                             $num=mt_rand(50,55);//优惠券金额8 F. U* e5 M5 H( Z& `) U' q0 Y' }
  23.                             $id=2;
    2 E/ ]# v4 f% N
  24.                         }
    7 O% Y0 i. P) `+ n5 v1 v4 m
  25.                     }
    ; V3 R& a+ E/ V5 z: l! V% b% O
  26.                     if(!$id){
    ; m8 _5 e. g( S8 Y" R3 |# S# s, W2 w% r
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    & R- @* s) o" _7 t4 D3 m* Y
  28.                     }else{/ h  `) ~  ~0 ]9 Y$ Y- j8 E* n5 |! K
  29.                         if($is_lingqu){
    " `+ w& ?  _3 |6 ^
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';" w0 L& v7 A9 [& S& c
  31.                         }else{
    & o& H- N9 [9 D) w& I: @% J6 Z
  32.                             //锁表  i  K' n# d3 |* n9 Q" L( ]
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    $ I0 X3 I- Q; s3 f0 b
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();& b3 z  J7 s/ Z
  35.                             if($active > 0){
    7 `7 ?  [. a( u/ v+ E1 ~
  36.                                 //开启事务
    " B( f( M3 I5 M8 p& K
  37.                                 M()->execute('start transaction');
    ( ^# X4 t- E6 b$ b
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    . H" _: c& V/ ^5 o1 X2 z
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    , a8 W' U. o2 H" {8 ~2 \
  40.                                 $members_preferential    =    M('members_preferential');
    ; L  F8 e( P0 X9 k5 f0 P
  41.                                 //对应投资金额,8 d9 e  w6 B" Y, H% h
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));. O3 u5 C4 h* l- O' \, B
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');9 o1 g  X4 W7 W! X3 S+ ~, Z6 B+ y
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间% b4 Q+ F' K8 S0 k0 U0 e
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ! D, `3 P! j: j; H. ]2 o
  46.                                 if($save && $add && $add2){
    3 [" E$ R0 Y! p0 m( s2 \9 m" F
  47.                                     //事务提交, R5 d: q; K1 A% c6 _  j. U! U
  48.                                     M()->execute('commit');
    ' u4 q" i, D) H) R. c8 m/ a
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    7 j" h5 J) V4 F! y0 r7 J" Q
  50.                                 }else{
    & F1 n8 i- a" S* B+ a% Y  r
  51.                                     //回滚
    : G" W9 O! i/ a  G! ^
  52.                                     M()->execute('rollback');
      X' l# N+ r/ H5 C
  53.                                     $data['msg']='未知错误!';
    / I# _. n% f4 D1 U8 T4 c1 A
  54.                                 }
    . z% A) t6 \' x- J- B1 p
  55.                             }else{
    ' ?+ Z$ h& f% f, C, o- U+ n
  56.                                 $data['msg']='红包已领完,你来晚了!';% H; W9 k$ U" b# U' W$ X; t
  57.                             }
    / J; e. T3 X4 Y/ R) s$ }* M) o. i
  58.                             M()->execute('UNLOCK TABLES');
    % g2 Y+ N8 e5 F% Z7 C2 F
  59.                         }
    7 Q' k& ?5 [- ?) O1 H
  60.                     }
    # R& E: l7 R0 C4 D/ z
  61.                 }else{
    % h4 N3 Y; F, S
  62.                     $data['msg']='非法操作!';
    4 J) U  w$ J/ K  ^/ g  a
  63.                 }! T: `, `+ ^" c) V+ H/ G) ]
  64.             }else{
    + U! {" r8 Y* M/ y) q5 R; H
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    4 x; G: t4 [* N+ C8 V7 F8 A
  66.             }. K- M3 ~9 C3 {- U
  67.         }  Z2 {/ i( g& g. n+ i) G
  68.         exit(json_encode($data));- }4 _7 A9 \8 ]
  69.     }
复制代码

" r, a9 w- k/ t' D' f# |& L
( H4 E. r& R& `6 N/ C
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 00:54 , Processed in 0.061670 second(s), 20 queries .

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