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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

- L: ~. o6 ]5 u" u: a# j
Mysql中的锁语法:
5 H$ p; X; V8 x& W" h& oLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】# V) K+ x* k5 s+ t7 @8 C% U5 ^) ^
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
3 @  M6 M! A! E* _Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞5 T! B* t, B1 c) n( X5 |8 P& X$ E
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :( D$ n; J1 j5 w2 V' y
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
7 v% \2 C' q: i6 f测试时,有个文件就行,叫什么名无所谓
总结:
" J2 |) O) |- A) u% s  O2 p2 h项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:" |+ P/ r5 V5 [
1. 高并发下单时,减库存量时要加锁
/ I. O6 V3 I& D' r' y+ D2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    . L7 ^; V4 f2 ?/ d3 n4 \) g. C9 E
  2.     模拟秒杀活动-- 商品100件; v6 [1 ]0 m. y# A& F: O  g
  3.     CREATE TABLE ta8 y) O3 X3 [/ n( m% b: t
  4.     (
    7 O) T) w" p7 j/ d) ^2 A- C
  5.         id int comment '模拟100件活动商品的数量'! K8 r- j9 ]8 F; z
  6.     );! ?/ l. M6 c& J  `) Y5 ^0 P
  7.     INSERT INTO ta VALUES(100);) h. d' `$ E4 B  C' u- d
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件: f' i8 w; a1 L
  9.      */ 3 D. d% O8 h( o, l% F
  10.    
    & D( V. r/ i' T3 {6 q5 f
  11.     // 关闭错误报告, v6 C: y9 s' f1 g1 ?
  12.      error_reporting(0);
    " J4 X, T3 p& ?9 R

  13. 8 P0 V6 E. D% V; K" D  ^
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    : A0 F8 L& f9 X+ ?( }! ^1 z
  15.     $dbuser = 'root';            // mysql用户名
    " N  k0 y# [2 \
  16.     $dbpass = 'root';          // mysql用户名密码
    3 r% t+ e4 y) B; A5 e
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    , q8 }0 E+ ?& o$ L: ]6 A
  18.     if(! $conn )
    $ T! R) ?2 W; E6 p7 V- s/ [6 N
  19.     {! C4 f7 D4 a( P/ U
  20.         die('连接失败: ' . mysqli_error($conn));
    . V, v5 P; c, W# x1 o1 }
  21.     }
    4 a$ K& Y5 I4 x6 `, R2 i: a" ~
  22.     // 设置编码,防止中文乱码
    & V8 @" j; k/ V7 w+ e
  23.     mysqli_query($conn , "set names utf8");
    " n) y9 Q9 m- H! i) x$ ~& k8 u* B
  24.     mysqli_select_db( $conn, 'temp' );
    ( e7 {% c4 H! v1 N2 K' j( n0 H) O
  25. 7 v5 u1 G1 F! q8 G9 x5 p
  26.     # mysql 锁
    9 _3 N: @4 Y1 r0 K! }5 s. {
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 1 c  O2 _) y# ^
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');   @. j. v, f3 ^" z+ N. L
  29.     $id = mysqli_result($rs, 0, 0);
    ' w' n$ A( f$ c+ h9 y( O- I8 t# ~) c8 {" I
  30.     if($id > 0)
    3 C9 ^3 L0 [- z% {4 z7 w: A
  31.     { 8 g3 h' r2 H& |2 B! y& G% Y
  32.         --$id; # ~% }) V  i3 E$ E
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); / {( ?6 ?! x% [" L
  34.     } 7 w4 o* `3 x* y7 U" c- r

  35. / k) z# V( a' H
  36.     # mysql 解锁 4 G, o6 G3 e$ Q' m' ~' v
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ' g0 A. x. U2 v% K) ?4 N- v0 y0 `
  38.     //查询解锁后的id值1 S/ o# `# n6 l9 a+ x8 B7 B4 ^
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');/ Q! d8 O1 n6 F9 Z. t
  40.     // while($row = mysqli_fetch_assoc($res))0 C; v1 ^/ S; |, S
  41.     // {
    # Q% S+ x: T. U' I
  42.     //     $id = $row['id'];
    ) K0 N; i# j! R+ v3 Y/ |9 ]3 ?
  43.     // }
    ( `2 B% j8 ^7 K' X
  44.     // echo $id;
复制代码
; g9 P- o. N& G5 ], U% q: e

; Y! w1 s" U/ W7 ~0 j' C

+ C/ q+ R( @1 \. t# x. I& n3 B. h
PHP文件锁示例:
  1. /*
    ! K3 N) q8 Z+ x% b: `8 b7 d
  2.     模拟秒杀活动-- 商品100件8 H, h+ L& a- `9 {7 v4 F
  3.     CREATE TABLE ta3 |7 \# f6 w$ d
  4.     (- J; J& U2 U& g( v
  5.         id int comment '模拟100件活动商品的数量'9 a& \4 N) L0 r3 M2 _6 O. n
  6.     );
    4 X7 b" v9 ?' {' r6 W- f
  7.     INSERT INTO ta VALUES(100);% J- r* c! h/ i# k5 J1 B, t
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件; E+ B8 d, h4 s3 a- L& I1 q
  9.      */
    1 }! R; L5 ^* [
  10.     ( G! c' y  j# J& B
  11.     // 关闭错误报告
    5 Y" H& o# v! T9 M0 B
  12.      error_reporting(0);
    . y* A9 k) e9 _3 q8 [
  13. 8 `% n5 ?" H: ?+ N, \" ]9 B
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    8 y) Y* i4 B4 W2 d/ I
  15.     $dbuser = 'root';            // mysql用户名/ o4 a$ S2 ^8 U: |& n5 K3 T
  16.     $dbpass = 'root';          // mysql用户名密码; W" S+ s5 T& `3 w4 {9 W3 s# U# j" \
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);8 v: `. h( v1 r6 t! u
  18.     if(! $conn )7 U# J4 P5 J9 Z& q+ L9 K
  19.     {; ^# Y8 b: E6 t0 M0 c
  20.         die('连接失败: ' . mysqli_error($conn));+ ~( H( d$ p0 w, ]+ ?
  21.     }  m( B- [  P# Q( _0 Q
  22.     // 设置编码,防止中文乱码
    ' R" O# k4 a5 \8 S& o
  23.     mysqli_query($conn , "set names utf8");
    ( w* v& m$ D$ X$ O  e1 ]" f
  24.     mysqli_select_db( $conn, 'temp' ); - k0 Y* l7 t% i9 M! L

  25. : _& A% q3 [" C- E% f
  26.     # php中的文件锁 4 L: A$ u0 y: p  |: d) D" L
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 : p( o# W3 [$ i" f% K/ K+ l) l5 n% S+ o
  28.     flock($fp, LOCK_EX);// 排他锁 " t: ]1 a& Q4 r3 t& b

  29. ' Q, `  V2 |. M& I" t: L
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ' K; @. Z% u5 u' S
  31.     while($row = mysqli_fetch_assoc($retval))- T: u. i( F. O0 M/ e% z
  32.     {
    & `& _2 E* T& f' Y  {3 l
  33.         $id =  $row['id'];
    8 v: Q# T9 l1 c
  34.     }
    3 ]% c( G$ P1 c# d4 v
  35.    
    9 n0 Y0 i6 c, ?6 W, E% B
  36.     if($id > 0)
    * [' Q9 z  o  h% V: l
  37.     { + y8 a5 U7 k, ~) j: S$ r) }& j
  38.         --$id;
    / V# y# [4 Y' `
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    * x" g5 @$ F) q. N' T6 U, t
  40.     } 1 y0 Z1 C  k; {/ p1 H% w, |, k
  41.     # php的文件锁,释放锁
    # U5 p& v8 @6 r9 o5 M( a% P
  42.     flock($fp, LOCK_UN);
    * X, W, G, s) ]% V; y4 z& A) z
  43.     fclose($fp);
    ) N$ [! r% ^) m  a
  44. , n) A+ P- {$ k$ B( ^6 |+ P
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ! l0 b6 S" \1 U- u/ e( t2 p5 u
  46.     // while($row = mysqli_fetch_assoc($res))4 ]# e8 M7 G6 F: r4 Y
  47.     // {
    + Y( [; @4 E& e* G6 t
  48.     //     $id = $row['id'];/ _! Z! p) D, @- n- g$ Q
  49.     // }
    . j: `% A# f! M
  50.     // echo $id;
复制代码
2 _( _) z, j2 O: u
0 U+ d; D% {* S& g) M7 j
抢券活动实例:
  1. public function envelopeSnatching(){$ d5 k: a: n8 v# ?# X0 U' w( y7 K
  2.         $lingqu = $_POST['type'];
    & l2 T) f2 ]' I3 Z! L
  3.         $uid=session('u_id');//用户id* R& y: ?, z& f: Q8 \
  4.         if(!$uid){
    ! p+ Z6 a; p. ]& R+ [
  5.             $data['msg']='您没登录,请先登录!';
    - K: I- {8 I, e, i* w/ K
  6.         }else if(date('Y-m-d') != '2017-12-12'){8 v6 D' S3 ^7 F3 e
  7.             $data['msg']='不在活动时间内!';* ~( d; f4 k' ?( V. V
  8.         }else{. i5 T5 m% _1 E' k" w
  9.             $hours=date('H');//当前小时数2 r5 e4 Z# i  v2 u. N
  10.             if($hours > '09' || $hours > '17'){
    7 y% ?' q3 l/ m

  11. 6 \" }) j; {" r, B% J* \+ Z
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    8 [  u* `! T: e* V) [! j4 a% L2 t
  13.                     if($lingqu == 1){* R. I4 f8 V* I, J$ L0 O% a. o) V: f
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过% p" m. Y! F5 S# n
  15.                         if($hours > '09'){
    , J' h  `0 C" |) j: e) k
  16.                             $num=mt_rand(25,28);//优惠券金额
    ' T* C' z+ N6 ]
  17.                             $id=1;+ ~* {. w1 E4 n' w/ R
  18.                         }/ g0 Q( [- ?9 @
  19.                     }else if($lingqu == 2){2 {( V8 k0 P  b0 H3 B! c- C, |0 R1 B
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    9 M; z! G: O4 r  o
  21.                         if($hours > '17'){3 t( d3 v7 i$ c
  22.                             $num=mt_rand(50,55);//优惠券金额
    & G# S" G. X/ t: H( H* s
  23.                             $id=2;1 F; _& v5 Z, s% e0 u
  24.                         }* d+ `5 c& u2 L
  25.                     }
    $ _6 Z+ g, m; w2 N
  26.                     if(!$id){
    % ^9 Y2 |' f& f6 f& N$ M" |" V  |
  27.                         $data['msg']='时间还没到,晚点再来吧。';/ {  t4 [8 t& ]0 _
  28.                     }else{
    / A) Q  g  ~) `
  29.                         if($is_lingqu){. A% O, {& V3 t7 u0 R0 Y2 Q
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';7 o) r4 G1 A# R* ]' @" e& p7 p
  31.                         }else{
    ' }( u) A' t9 R0 \* x4 A
  32.                             //锁表( ~3 b2 m8 x7 x7 f$ C1 P- g, N6 Q
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    % q6 z) F- f+ W# x% k0 y+ t
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();# s2 x% Z9 G  j) n, }' \
  35.                             if($active > 0){" O3 R: o  a8 k* r
  36.                                 //开启事务# v; h/ }8 l3 ]2 x
  37.                                 M()->execute('start transaction');  M& \9 Z' o2 s! e8 b. I+ ^# o; [
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    ! P) y# u; S0 M# }
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));5 B! i* U: M  [3 p. [( u# s
  40.                                 $members_preferential    =    M('members_preferential');
    / W" b# v' d: s
  41.                                 //对应投资金额,4 _: u5 u- a0 m: Y" a  C% d
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));( k; c3 E0 s: e- k
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');/ @9 j5 P% b3 Z) O3 o
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间7 h  x" n5 _$ g- a4 Z" }
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券+ P% |7 ?( e2 E6 d' E/ S% ]
  46.                                 if($save && $add && $add2){+ ~* Y; i* J3 ]; R  Z! }- k
  47.                                     //事务提交
    * Q' @$ L/ |# H4 @7 U( N
  48.                                     M()->execute('commit');: H! }3 h3 M( T7 A4 c& Y& R3 i
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    ' N( W5 H0 `+ g% r
  50.                                 }else{
    4 ?& P8 w8 Y6 Z5 E$ l4 E/ M
  51.                                     //回滚
    2 ?8 v! l: E. a  `5 b
  52.                                     M()->execute('rollback');. y4 d9 H( i7 L( Y
  53.                                     $data['msg']='未知错误!';( `* D4 |' h; [' l% X1 z
  54.                                 }
    $ O0 o6 ^# T5 Y
  55.                             }else{! g9 n4 Q9 {3 `6 Q% q5 m
  56.                                 $data['msg']='红包已领完,你来晚了!';6 p7 b$ [' B( k
  57.                             }
    , M# p; N! T. N. \8 {
  58.                             M()->execute('UNLOCK TABLES');2 ~1 o5 W3 {+ @& l( m/ Y/ H. [0 [
  59.                         }5 r. y6 Q( g. ?+ f$ X& k& U( J& T
  60.                     }8 q3 W6 e5 j  h
  61.                 }else{3 Y6 f) f0 `: N1 J5 _  {: w
  62.                     $data['msg']='非法操作!';1 ?" F% E( Y; |( s- m* e8 H% K# Q
  63.                 }' J  j# @% n# T
  64.             }else{
      u$ c+ l, @. ?' i3 o% R
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    8 @/ h% L4 K* ]$ ?
  66.             }/ w2 d5 Q2 {3 E# K# T9 Z" ^: B
  67.         }
    : p1 T5 Q( `/ [2 g; O* I  [
  68.         exit(json_encode($data));7 ]3 k% q- {- e0 M$ x3 A$ B6 S' Y% R
  69.     }
复制代码

0 V2 C" b& {, o& q- X! E1 Y  m: u& B$ y" ~) J" J4 n' [
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 19:04 , Processed in 0.063299 second(s), 19 queries .

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