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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

9 J7 O+ K1 \! q1 O
Mysql中的锁语法:# L3 f* F! C& {) T) y$ ]8 m
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】% l! }) D3 |( M- n9 [% R
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表7 V) `8 t  A5 j. [6 I6 I
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞9 b) w- i0 S% b0 R
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :( A5 u% O+ d; m1 c. _, ]
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
: D+ e+ P  I' F: Q* x测试时,有个文件就行,叫什么名无所谓
总结:
( l/ Q( p7 `2 Q- s* @项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
) g/ U. J8 N- j3 c# m, U1. 高并发下单时,减库存量时要加锁& x# ^) ?: G* W) r3 P
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*: @; T9 z' _$ y
  2.     模拟秒杀活动-- 商品100件
    % A' t* {2 P6 v- }
  3.     CREATE TABLE ta
    6 ]" Y5 x; F9 X% I7 e& J; J6 o3 H
  4.     (
    + P  A3 Y$ L+ G- Z, X
  5.         id int comment '模拟100件活动商品的数量'/ M- f& b+ R9 v+ w6 {( Q# x4 B
  6.     );
    . L' {$ y7 G9 h; H
  7.     INSERT INTO ta VALUES(100);
    6 L  ^: i# z% r$ Z& v( F# r
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件' ]! h6 v2 i  @# }7 p4 S2 {
  9.      */
    # }8 V0 R. c% ?8 t' F
  10.     0 c6 u( x* }* d  s1 `+ G% ]6 v
  11.     // 关闭错误报告1 s8 A7 U; H8 ~: w
  12.      error_reporting(0); ( v) l4 M9 e, V5 N3 o4 y
  13. 2 ~! n) [  B# g  o: Q* T8 x
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    5 F- K; O7 x, t8 S. r9 ~; ?9 j/ o9 e+ e
  15.     $dbuser = 'root';            // mysql用户名$ H# t0 N5 \& V, A" D+ v: R: u! s5 V& e
  16.     $dbpass = 'root';          // mysql用户名密码4 T4 w5 A5 s8 l, V4 a" S+ r7 m
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    5 E0 z% L1 n" [4 s3 w5 Y) y
  18.     if(! $conn )
    ' `( C7 \4 Q' O' ^6 g
  19.     {
    ' F6 a2 H$ s8 c8 c" x2 {
  20.         die('连接失败: ' . mysqli_error($conn));
    ) g% i1 Y1 e) \& x7 g7 T
  21.     }$ f$ L9 D. `4 w: Y( C; h/ u0 f
  22.     // 设置编码,防止中文乱码& S/ W- C! o" L: E& d. D/ |9 N; Z
  23.     mysqli_query($conn , "set names utf8");
    ; f, }+ j: V; p1 {# o& C
  24.     mysqli_select_db( $conn, 'temp' );
    5 @; X3 O8 G1 l3 ~8 ^: ]- E
  25. ' x: o# F8 H4 V, F; U3 L" F
  26.     # mysql 锁 " M6 v, a' H4 G
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    8 V) K6 g. @3 K, R
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    : V* Y: i; ^& k+ o' Z* n6 W
  29.     $id = mysqli_result($rs, 0, 0);
    3 n$ G, u: q: e# l1 A: U4 }* P4 k3 [
  30.     if($id > 0) 3 p  ]) y$ B( s5 H, c
  31.     { ) [4 Q3 m4 g  P) O& W* [
  32.         --$id;
    8 _# \* K% `6 n1 t6 y0 s
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    . h6 S0 P8 d% u7 N1 Q$ i0 }& E
  34.     } 2 _* d8 v$ x8 G% }
  35. 9 ?. M6 p  a: R3 N
  36.     # mysql 解锁
    . y7 J( v) }+ u# t: `' \! H5 I* h
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ; K1 F* Y& g9 F( M4 {- B3 `& d
  38.     //查询解锁后的id值
    2 x5 p! R+ r9 m( Y
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');% d; e( s  y. Q! p- ^# z. b% p6 e
  40.     // while($row = mysqli_fetch_assoc($res))5 D9 }; t: q# T6 s4 b5 f
  41.     // {
    ! u" b* g0 f- L- G, M, O
  42.     //     $id = $row['id'];
    + c. X! B0 O: c
  43.     // }$ r- f% D4 Z8 P1 x1 G
  44.     // echo $id;
复制代码

4 Y( V( @- b3 _! M$ ?! a/ q( Y" ^6 M$ \( q8 ?4 T% a; X4 C
! t5 [$ _' k( K/ c0 y
PHP文件锁示例:
  1. /*3 O- t5 @# n; O. s0 M$ i
  2.     模拟秒杀活动-- 商品100件
    & [2 q2 p! Z. Q. F
  3.     CREATE TABLE ta
    + ~5 ?) \7 J0 N
  4.     (0 g% j! [, Q# E- J- L* r; }3 _9 I
  5.         id int comment '模拟100件活动商品的数量'7 y, Z! T! `) V8 G5 |8 z" E
  6.     );
    9 D# k' q* n+ R, F3 r+ S) N* e
  7.     INSERT INTO ta VALUES(100);. [/ O* s  \3 w- n5 G0 i* ?
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件$ ?$ a( y& k0 c5 T
  9.      */ " N8 \9 m) P* ?5 ]
  10.    
    3 U6 E: L& k# v. g; ?9 X
  11.     // 关闭错误报告' c( w' r" @, J4 z: p$ ?$ ?
  12.      error_reporting(0);
    & p1 V9 t- v. G* f
  13. " I/ n( U+ d4 L+ |
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址. \9 r- O2 Z0 W0 t5 M) X" Z
  15.     $dbuser = 'root';            // mysql用户名' b2 O0 j( W2 ], b% o% ?! Y/ W
  16.     $dbpass = 'root';          // mysql用户名密码
    4 {) u: D  v- b  A, x
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ( P  _+ L' O4 K( N0 [2 q4 n) D
  18.     if(! $conn )
    * W+ {6 i% R( O% _7 ]; O" i
  19.     {# L( M/ _. G( ~( k9 S) o
  20.         die('连接失败: ' . mysqli_error($conn));) N6 A! Q5 o: l; g* W
  21.     }# d! W3 t* I/ x% @  L$ k: g
  22.     // 设置编码,防止中文乱码
    ( w8 f4 S- ?" F; k: H/ r2 Z3 ?2 v
  23.     mysqli_query($conn , "set names utf8");: B$ B1 Z( P1 |4 N
  24.     mysqli_select_db( $conn, 'temp' );
    $ q% ]4 D) ]8 g+ t1 |* V
  25. 5 B3 M$ P" I- [$ @' y8 b5 |& g, M
  26.     # php中的文件锁
    ( e: l7 n7 o& n. Z
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 ' O7 u4 h  W+ c% s" _/ @% W
  28.     flock($fp, LOCK_EX);// 排他锁
    - z5 ?& d' s7 Z/ R
  29. 7 t3 r  e9 C' Q9 O' e8 f7 Z0 |$ Y
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    8 f* C, {, F* z* r6 E- c
  31.     while($row = mysqli_fetch_assoc($retval))
    3 J; q  D+ j) }" |3 _+ Q, @
  32.     {
    - t% ?/ Z) F/ i7 W0 [( v& E
  33.         $id =  $row['id'];
    - x* R, E/ b% O6 B" R
  34.     }
    2 M6 P& w0 Y! S9 R" k. }
  35.     ( k6 c4 P: K5 u5 V0 }
  36.     if($id > 0) 7 N7 Y- e0 x0 ?! Q. h$ g
  37.     {
    . ]4 ]8 S( h8 I9 V* O
  38.         --$id; 0 `; n" @& W7 ]8 l0 y; S7 r
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); * ?2 ^  _! m: Y
  40.     }
    5 V  G' C4 q  s, p' i$ {
  41.     # php的文件锁,释放锁
    1 _2 [( x) b* [. \" c6 o
  42.     flock($fp, LOCK_UN);
    ! v- M, P" _, G7 V' P
  43.     fclose($fp);) w! I1 v  `8 [, N
  44. ; b: }) M, J. v3 e: I0 k- y
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    9 u, j& `8 j; ]$ p. C7 r
  46.     // while($row = mysqli_fetch_assoc($res))
    1 D5 _% F# G% i- ^: c, c8 q' R4 V
  47.     // {
    * Q! L' u) i% U! n- M% U/ u, E
  48.     //     $id = $row['id'];2 i7 `; C/ Z0 U) d5 g# s. h# I# R
  49.     // }8 W6 P/ ?  h/ U# o2 Z: V6 T
  50.     // echo $id;
复制代码

* \& A- r8 K+ Q5 S7 _0 T. x7 x; M6 |/ W: P/ x8 i
抢券活动实例:
  1. public function envelopeSnatching(){
    - T. ~3 t0 H* K1 S: S0 l
  2.         $lingqu = $_POST['type'];
    2 t, A/ c) r  n( b$ z8 _/ Y
  3.         $uid=session('u_id');//用户id! _  Q  l2 Q1 h8 ], ]
  4.         if(!$uid){+ o  M4 r3 Z( o5 L9 g4 V! O: R
  5.             $data['msg']='您没登录,请先登录!';. z0 [: c; X. y0 k
  6.         }else if(date('Y-m-d') != '2017-12-12'){0 m8 j. O) ?* `! u$ m0 T
  7.             $data['msg']='不在活动时间内!';
    - C/ [8 s. j; y) g/ W. n
  8.         }else{
    9 S- I, Z* w; P# V, {) A% `
  9.             $hours=date('H');//当前小时数
    6 I/ I1 x" m* U: a' p
  10.             if($hours > '09' || $hours > '17'){
    5 d+ {4 p  y, g2 j6 Z  M

  11. * R' M: s: B+ Y+ T
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的7 u: x4 S8 `$ J8 w+ Z- H0 h9 ?
  13.                     if($lingqu == 1){
    $ J8 W! o; \$ q; f/ s& m7 @6 y7 e
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    7 M# G% E" ~) p! Y+ b
  15.                         if($hours > '09'){
    " W, m9 b6 u( i5 R9 Y6 z+ i  ?
  16.                             $num=mt_rand(25,28);//优惠券金额
    . N# Q& A. }0 v3 j6 j) ]+ O
  17.                             $id=1;9 u+ R4 a  Y; Z, A5 N3 p4 w
  18.                         }
    6 s, r" [& M: p7 _& {
  19.                     }else if($lingqu == 2){: T0 Q! k  Q; x% N
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    + P- k8 C- K5 f( ]' }2 _* I- i( w
  21.                         if($hours > '17'){
    : \/ T+ [% f' `/ j
  22.                             $num=mt_rand(50,55);//优惠券金额% }; e9 r7 @. s0 z* {' `
  23.                             $id=2;
    2 @4 ?$ G+ D. {7 n/ f: h( H
  24.                         }( W8 J2 ]  Q' M1 m6 {* v
  25.                     }
    " H" t$ P7 E  w. y9 R
  26.                     if(!$id){
    5 {2 v! b1 h+ d  \! f1 c- B
  27.                         $data['msg']='时间还没到,晚点再来吧。';0 F$ w1 n0 C+ @1 E* c
  28.                     }else{, u( l/ T" v! W# G8 U/ o
  29.                         if($is_lingqu){
    - ^& v  M2 L% a
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    : M) G! z" L- G/ m
  31.                         }else{; R) {5 E( b' A; L- P% h' o
  32.                             //锁表/ c! B& I0 z" w1 h% J6 K. i
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    - s* _2 @. P; Z# J( n' K
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    1 D. V. C1 P% W1 ?& w* Y$ [8 T
  35.                             if($active > 0){6 [& @3 L" g' s* l
  36.                                 //开启事务- @2 b0 }# F' g) M5 r0 E* ?" K. I
  37.                                 M()->execute('start transaction');! v' H8 e" I) b: J+ N9 R
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    # x1 {* V: Z' G+ h4 Z
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    4 w9 O4 d3 [6 [5 [* t
  40.                                 $members_preferential    =    M('members_preferential');+ `' e, T* |* e: F9 D- G5 G  k
  41.                                 //对应投资金额,4 P6 u- I! _" X" I& c4 L
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    6 t* s" N- l( i
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');" [* C: w+ c& \  c9 O6 b8 p
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间- {% G. K2 A. w8 X8 N
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ! R9 L; {% u5 U" f! ~+ {
  46.                                 if($save && $add && $add2){
    3 z" x7 E, \: k7 P" s: X+ R" L
  47.                                     //事务提交
    , G/ R! y" c. T, M. j
  48.                                     M()->execute('commit');
    & m# Z. M: _1 v3 ]# z% c
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    / y3 I' t5 K, Z0 `
  50.                                 }else{! Z7 M8 {6 I8 i8 w
  51.                                     //回滚! F' k# {# e% q
  52.                                     M()->execute('rollback');% b! x1 E* f. j; ?2 [
  53.                                     $data['msg']='未知错误!';
    3 A1 Q$ s/ z1 {; j& h6 }
  54.                                 }
    3 V7 p! D( J3 M* Q- G" r- F8 K
  55.                             }else{
    ' h& v$ g( G6 t0 W" K5 y# J& V$ ]7 V
  56.                                 $data['msg']='红包已领完,你来晚了!';& ?! W* j/ r8 E' u, [
  57.                             }
    + n; _; x) I8 ?2 s
  58.                             M()->execute('UNLOCK TABLES');
    1 `& p9 b: s2 e( C' r  p
  59.                         }
    6 ~- }; t5 q! K2 F
  60.                     }0 a+ X# W1 ?9 O4 t7 L5 x
  61.                 }else{
    " E) o8 z  v& A# |1 r/ b  y
  62.                     $data['msg']='非法操作!';9 U1 {7 `- ~7 |( L4 [4 T  k
  63.                 }4 \# K, W: K2 C  E
  64.             }else{
    ; t$ P, H$ c# b# m* C  ?
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';) H$ D6 x# i0 G9 ^  c0 @& Y
  66.             }3 j" L) l, A& @6 {
  67.         }2 x% ?3 ?: Z5 n( f
  68.         exit(json_encode($data));( a! p% \1 w; Q0 J  f
  69.     }
复制代码
4 g5 P& ]: Q4 w$ y; j- i

5 w, R' R/ d% d) p1 i. r
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-7 22:05 , Processed in 0.121813 second(s), 19 queries .

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