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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 5726|回复: 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://请求的脚本
复制代码
% n/ i& ~( f5 M! F. \) x" x
Mysql中的锁语法:* s5 }& L# @0 v) b/ m/ h* u
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】# c0 d+ s' k4 b. X; n7 N; A
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
' X- j- {9 r- `. m8 C8 |Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
" g7 Z* D4 M$ j$ D  k9 k) l$ \注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
+ L8 L1 {2 Q& I' }  m文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
. q5 P7 ~/ X8 D( X7 o! n1 w, h测试时,有个文件就行,叫什么名无所谓
总结:
. Y0 ^& O/ [' J$ k8 k  ^  o项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:0 `  z8 L& A& A/ y& G& G
1. 高并发下单时,减库存量时要加锁
3 U/ \7 `* q6 U& |0 \2 d2 t2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*& S( [8 ^- ]( f. m
  2.     模拟秒杀活动-- 商品100件1 f4 [' o  P" C2 b8 I( W, q
  3.     CREATE TABLE ta" m+ c6 W: L- U" C* V
  4.     (2 S. V; [8 |8 P! p( c
  5.         id int comment '模拟100件活动商品的数量'. x" A3 @. Q. E7 p
  6.     );
    + n' D, P- c4 F6 d6 T( z
  7.     INSERT INTO ta VALUES(100);
      s% x0 Z! S+ e: S) `
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件" ?7 d, Z% s; b$ O% b1 l4 I
  9.      */ ) i0 D( V+ g8 o; [2 u1 ^
  10.     ! S, H6 Y- f# K# p9 p" K3 p
  11.     // 关闭错误报告
    " Q3 t  U% k  T* h
  12.      error_reporting(0);   i3 N7 N& v0 _6 _6 m

  13. + s* e) F& |! @3 v; a
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    . `8 X' m; q% M5 |2 s
  15.     $dbuser = 'root';            // mysql用户名" ^# ?7 f& f$ P# Q% d) `
  16.     $dbpass = 'root';          // mysql用户名密码
    ! h4 g7 b. A  H
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);. `, e$ t9 L, V6 Z, e
  18.     if(! $conn )
    ) q4 K% s$ v( N2 a  Z0 f) q
  19.     {
    ; c8 {' X% G1 z/ Q
  20.         die('连接失败: ' . mysqli_error($conn));( y) F- o0 a! r& P/ a
  21.     }
    0 t( O- q9 s2 e' m4 X
  22.     // 设置编码,防止中文乱码+ I1 X0 O. z  k& b2 R
  23.     mysqli_query($conn , "set names utf8");
    ! V! ~5 f# @- z, C- C9 r
  24.     mysqli_select_db( $conn, 'temp' );
    7 j; g8 A( |, U: ~, p2 K2 b( r

  25. . ^0 _. Q( H( u; @, x
  26.     # mysql 锁 " m; c  s, ]& C% `
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    , _! ~1 e* M+ o  i9 U. a
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 4 H2 @# y) n* W3 F$ H) M6 o
  29.     $id = mysqli_result($rs, 0, 0); 6 x5 V" C* J3 I& ]& U
  30.     if($id > 0) , `7 c# w0 f* X4 u( F1 q5 O
  31.     {
    0 B2 X5 H  o; T3 j! U2 y
  32.         --$id; % s2 T8 R7 ~' @8 ]
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    # w0 L$ J' e- _6 v, |. q
  34.     } : R7 l! \6 ]! K' i6 x& `  x8 e: A8 z
  35. / A5 m, x' C* Z' Z0 T7 u1 f0 R3 i
  36.     # mysql 解锁
    2 e( N1 S8 @9 E
  37.     mysqli_query($conn , 'UNLOCK TABLES');8 [; ~' u2 t0 R# ^" ~# O
  38.     //查询解锁后的id值
    ( [) `7 R; c" K( H  F1 z3 Z* @
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');2 a7 Q! K3 j: _% v2 g& ]  B
  40.     // while($row = mysqli_fetch_assoc($res))
    ' d" _1 m! V, c$ P/ S0 `3 ]
  41.     // {
    ; c. v: P9 Q1 j% F5 v) H. U# J
  42.     //     $id = $row['id'];4 s9 ]  o5 \) D& M
  43.     // }' N! s- T8 I0 i7 H. p* J+ X
  44.     // echo $id;
复制代码
3 ?/ B1 }4 i' O: a( X' V
  R6 R# s' K  p4 Q9 K% g- G" e

: G3 H3 R/ m" c* \$ W# m/ G
PHP文件锁示例:
  1. /*
    / l- x) \% J$ z! h$ f0 v7 u1 }: L! I
  2.     模拟秒杀活动-- 商品100件2 j1 F" m1 X+ O( p8 @8 F( l
  3.     CREATE TABLE ta* N" Z% A9 b4 t; [
  4.     (
    $ v) C) M, _6 V- T; Q
  5.         id int comment '模拟100件活动商品的数量'8 F1 ^& e0 X' P* p* \
  6.     );
    ) P. c' e# q- S9 u0 I% ^( d5 Z
  7.     INSERT INTO ta VALUES(100);) d* i$ W; O5 ]! N. [: C
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    * G! b+ B* t" y5 Q
  9.      */ " U- X7 f% Y( ^; o
  10.     - t7 G$ t0 k$ ?6 d) u
  11.     // 关闭错误报告
    + a$ K+ W0 m) v/ o) A% v; t
  12.      error_reporting(0);
    % H0 h! o8 T$ B: S
  13. , o; ~# k0 v7 V8 k2 s  n4 |/ n
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    4 b, h4 H6 x( l; q5 S
  15.     $dbuser = 'root';            // mysql用户名
    5 u) R7 \/ v# J: I* q9 K
  16.     $dbpass = 'root';          // mysql用户名密码9 V( ]2 E1 C0 }. v+ ?3 t& w
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);6 H* g% ^  f: p" U9 m
  18.     if(! $conn )
    ) l+ V* `& |3 K$ J, [: m3 p8 F
  19.     {
    / P' @- X0 o* M9 G1 @1 F6 Z1 o
  20.         die('连接失败: ' . mysqli_error($conn));. W% U, T. U# R$ o
  21.     }
    : o8 e, ~! X, V" B
  22.     // 设置编码,防止中文乱码
    8 O  p$ a" q, I+ E
  23.     mysqli_query($conn , "set names utf8");
    5 n: Z( k3 {9 V9 U; P. b8 v2 l3 m" r
  24.     mysqli_select_db( $conn, 'temp' ); 5 R! ~/ z1 X1 Z" O% M! T

  25. $ S# [: j) g5 m, o, R3 o: ^/ P
  26.     # php中的文件锁 % v3 L5 G  _" A& H+ U. q
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 - o3 V& ~9 X$ B5 u
  28.     flock($fp, LOCK_EX);// 排他锁
    % P+ W2 g" r3 V; r. L. }7 Q) ~6 T+ H

  29.   m9 W+ Y1 n: m% u# V7 Z, B
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); % N* I7 J% B1 l) N& e0 P% t/ ]! N
  31.     while($row = mysqli_fetch_assoc($retval))
    ; E- ^( o' b7 l. b9 O$ c: t7 R7 X
  32.     {- t2 s( ~2 G+ S+ U3 n
  33.         $id =  $row['id'];% G' X* L$ \1 w6 h
  34.     }
    ; X+ W$ G- A; q, c% T
  35.    
    & q  O% _6 V) Q
  36.     if($id > 0)
    ' F9 S* z. A& e' W4 G/ H
  37.     {
    * [3 J, d7 ?3 n
  38.         --$id; : n; {1 Q) p# f
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    , ]) d+ L0 y2 q2 V* v2 m( p2 V
  40.     }
    * t, r4 a$ t- E" @4 G& g, z4 t
  41.     # php的文件锁,释放锁
    / n! X+ L. M7 m  s
  42.     flock($fp, LOCK_UN);
    6 x5 |4 l! ~, B7 }/ O! d2 B2 l
  43.     fclose($fp);
      f6 M8 F- V0 ?

  44. ; Z8 r3 ]8 \  c
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    5 e* H/ R' n# A9 F
  46.     // while($row = mysqli_fetch_assoc($res))9 E" }7 ^) b& |! V0 M; W
  47.     // {
    ) e% p7 _' x* c2 s6 |8 P$ K9 `
  48.     //     $id = $row['id'];/ o# K2 \! i: M3 q' F+ I1 @
  49.     // }) C1 K* Y/ |! S9 T: }
  50.     // echo $id;
复制代码
7 }1 I5 I) E' `& b# m
2 v, f& Y( _& [, @8 l  v% `
抢券活动实例:
  1. public function envelopeSnatching(){
    ) `9 d# x/ }& o. G- r! P0 f
  2.         $lingqu = $_POST['type'];
    ) W7 O( n4 v5 D1 y
  3.         $uid=session('u_id');//用户id; _# V& }4 f) J( P" n( M
  4.         if(!$uid){& c; N' I3 E) Z8 j0 y+ ?
  5.             $data['msg']='您没登录,请先登录!';- L& [- u+ }; T" G! v3 L# ?+ S
  6.         }else if(date('Y-m-d') != '2017-12-12'){$ m- `8 e$ b) r3 o1 k( h
  7.             $data['msg']='不在活动时间内!';
    ! F# ~+ D- q/ z' ~$ @9 Q; @
  8.         }else{
    ) [' p. ~% \% s" Q/ f. K8 D
  9.             $hours=date('H');//当前小时数
    6 J" b% q: S0 G6 L8 a
  10.             if($hours > '09' || $hours > '17'){
    ! }% ?2 g1 l7 N/ u
  11. # t( z* M8 S6 Q2 S" l
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的8 A$ W% Y  ?8 I6 v
  13.                     if($lingqu == 1){
    5 T: v. G% |4 q, `
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过" }* K& B! x9 H
  15.                         if($hours > '09'){
    3 `1 f) I4 Z. Y! s+ P
  16.                             $num=mt_rand(25,28);//优惠券金额$ ^% P3 [! q( J! k
  17.                             $id=1;
    ! e+ _9 z! @, r/ I
  18.                         }
    ! V; G7 m/ z; S
  19.                     }else if($lingqu == 2){6 ]* Q, Y6 X6 g
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();5 B9 B% p9 P8 _+ [/ ?/ v7 I8 r
  21.                         if($hours > '17'){2 E1 l6 Y8 h  m5 c7 r5 \
  22.                             $num=mt_rand(50,55);//优惠券金额) M" x# A  ]0 P: H
  23.                             $id=2;
    5 i* v3 b0 h1 h
  24.                         }, j- @" b8 H" f7 G
  25.                     }
    4 ]( A% m; |/ R2 O. `2 Z' `3 d
  26.                     if(!$id){; r$ Z' O+ L& o
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    6 X* Z5 B; w2 [/ n) F* x
  28.                     }else{
    5 W; o0 {! \! f6 A
  29.                         if($is_lingqu){
    6 c0 S9 ]9 q% J6 I( j+ A4 f
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    & M) p5 Z) l* x, C$ m  j
  31.                         }else{4 o% [$ U# s0 s" T3 T$ F6 ~
  32.                             //锁表
    6 P0 U/ r# K. z: e
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    3 X9 Q6 f6 y6 `0 K8 S: \+ ~: y
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();& s$ Q4 N" r, i( {4 {+ C' `
  35.                             if($active > 0){6 {, U  Z& O1 {. O) V/ i1 O
  36.                                 //开启事务7 U% Q% S7 A$ O4 y
  37.                                 M()->execute('start transaction');( o9 V# |& V+ U, ?$ k8 i/ b
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));9 z# ]9 X% t2 ~( @( W( ~  Y
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    ; L) y6 @4 H) {% `; V
  40.                                 $members_preferential    =    M('members_preferential');3 {7 b% t  ~  q1 l6 |7 y
  41.                                 //对应投资金额,( b$ q2 x5 ?& q6 d9 X$ ~4 \
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    4 w  p0 a; |/ J, `! i/ g% R, E
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    ; A( m% N7 Q. i. `* v
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    5 z: x( x5 y1 c5 Z$ }1 [3 u! w
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券. [) O4 h  _$ C3 ~( U1 [$ ]5 A2 H
  46.                                 if($save && $add && $add2){
    6 F9 C$ [# v. N4 E7 p: j
  47.                                     //事务提交
    : c( `) L2 y9 A" P) B
  48.                                     M()->execute('commit');
    1 Y$ C1 ^7 p- ~( G) L/ S( U5 ~2 D
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    / ?) y0 j0 h$ w0 W7 m; k$ I
  50.                                 }else{' ^4 G5 N& e$ O2 g3 K+ x# W
  51.                                     //回滚# }$ g2 E  |! e$ h" Q: R  ?5 Y
  52.                                     M()->execute('rollback');' ~+ u; r6 e2 v& ]
  53.                                     $data['msg']='未知错误!';
    / }2 d3 v) V8 C7 H! P+ `
  54.                                 }! s; I( c  C6 u% u4 c
  55.                             }else{/ P2 u. A$ h! l% S2 {- \) |
  56.                                 $data['msg']='红包已领完,你来晚了!';" j5 g7 r5 ^& ]: P; K/ c7 L% \; y
  57.                             }2 X: K0 `1 h+ a, [
  58.                             M()->execute('UNLOCK TABLES');
    . g! G7 |$ ~0 z1 X: Z
  59.                         }" R, D$ F! J, n/ y9 y
  60.                     }5 O5 b8 k( ~' V' E1 o# w9 i' f/ T
  61.                 }else{; c" U% ]2 B  A
  62.                     $data['msg']='非法操作!';
    0 T( k  Y, p4 h7 e1 q: R
  63.                 }$ l9 h3 A* S( V; w( o
  64.             }else{+ ~* p2 E. {9 ~( h$ S
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ( Y) u1 K4 p! R$ E; S+ B. W! ~
  66.             }
    4 w: @$ C! |0 K7 J. _
  67.         }
    7 b& ?2 F4 Z$ e3 V& ]
  68.         exit(json_encode($data));
    ) i7 I3 ^2 I9 r5 }' C
  69.     }
复制代码
6 F1 N1 d. T: E2 L* f# {( r
- |3 t' H4 v, U+ ~3 c
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 10:25 , Processed in 0.101314 second(s), 20 queries .

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