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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8891|回复: 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://请求的脚本
复制代码
. Y7 j' W- G" ]' r2 ~
Mysql中的锁语法:
% D+ |: z* K) g* N6 KLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
# H, d- q9 k+ |* w! K" ?4 i! AUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表8 P* n; N  v* g
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
  n" X5 z8 p- ]- K2 Z/ O% |注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :2 M% c# e5 j: z7 \" a/ {) X8 `; \
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
( ?/ E6 L4 ~! F" B测试时,有个文件就行,叫什么名无所谓
总结:) V1 E/ c; ^9 c) V, d+ L
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
0 }% U" i) A) v- G$ U# j) X1. 高并发下单时,减库存量时要加锁
4 G8 c; [8 U$ D, v' |' S2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*$ P& ^9 V" j* n  B3 ]/ v
  2.     模拟秒杀活动-- 商品100件
    ( J5 F% a5 w* _" t" a8 i, A- V
  3.     CREATE TABLE ta( M; E5 Z0 z+ s) ?% J' |6 P
  4.     (& m2 _7 `' T; E" t, M2 I
  5.         id int comment '模拟100件活动商品的数量'
    % E) v# g# S2 C
  6.     );3 i1 M) n  n8 k1 d, S7 r
  7.     INSERT INTO ta VALUES(100);/ m6 g7 |: h5 O: U5 l
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    1 ~! y* X( d* I
  9.      */ # |3 q3 v: m4 X5 k6 L. n
  10.    
    & t5 Y8 w; z& ?# M
  11.     // 关闭错误报告
    , |6 l" b4 J0 ~
  12.      error_reporting(0); 3 h4 O# C5 a# |7 a% r1 I

  13. ! v( ~8 I, O9 s4 K- Q
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址) Y8 G7 O$ {* A4 B( m! @; p. _
  15.     $dbuser = 'root';            // mysql用户名
    * e; U% y% Q, b. q  @
  16.     $dbpass = 'root';          // mysql用户名密码& T* ~" d; H! R, Q- C
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);3 w+ W+ r0 t5 Y; ]# ~* g
  18.     if(! $conn )) M7 Z6 f- x0 Y$ G1 B8 E. U
  19.     {/ p% p; H3 b1 P4 b
  20.         die('连接失败: ' . mysqli_error($conn));
    4 X  L) t$ e! \) g, |: z/ }
  21.     }
    # J: W& P, j" t
  22.     // 设置编码,防止中文乱码
    ; j" ~* N8 P7 o- L$ e
  23.     mysqli_query($conn , "set names utf8");
    * P& C- u* [. T, n
  24.     mysqli_select_db( $conn, 'temp' ); . x/ K4 j& R- K* p, |
  25. + X  R6 y$ m. J. o( G' [3 I
  26.     # mysql 锁
    # M( s! Q5 t9 W; l$ }: o; a
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    2 r! _3 ^8 x' Z
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); : p9 ?: O' {7 L0 a+ y5 g; J
  29.     $id = mysqli_result($rs, 0, 0); 2 f$ q4 Y1 Z. K) z) q
  30.     if($id > 0)
    2 M/ u! o# T/ k4 E) V  {  l( p' h
  31.     {
    3 x6 q/ |# u6 g: c# e" Q5 C: w& o3 K. s
  32.         --$id;
    ; [. Z5 s! n. y, b# w
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
      V& B4 v5 T2 r9 a# q' T
  34.     }
    $ S1 |; c0 V) D) f4 X
  35. 8 Q: H; `7 H" ?9 S
  36.     # mysql 解锁
    + i! R; M" ?* W0 \* y" |2 J) ~
  37.     mysqli_query($conn , 'UNLOCK TABLES');5 I$ P- s* e2 V8 e( O* H1 E
  38.     //查询解锁后的id值& G: G; I0 Z% C/ j
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');/ J8 k' V7 H4 W* k) x$ v* _' I
  40.     // while($row = mysqli_fetch_assoc($res))
    ( g2 w: f! d! Z7 B
  41.     // {
    3 v" M. H' T* W: Z7 p3 n5 J
  42.     //     $id = $row['id'];
    , c8 D. b, E$ y5 E0 `
  43.     // }. ]; b" Y# Z# n! i# S: n4 c
  44.     // echo $id;
复制代码
( d+ s* I3 M9 W, x4 C2 T! C

) f6 v: O: w% ^
% Y0 A- f* L6 {) r
PHP文件锁示例:
  1. /*
    , l4 ]; r2 V5 _6 z6 y/ l* i
  2.     模拟秒杀活动-- 商品100件( M7 |+ G2 v) ]8 ^9 [- V
  3.     CREATE TABLE ta7 [7 q% a( c/ `3 b% |2 }
  4.     (
    $ T+ Z' l/ r' y
  5.         id int comment '模拟100件活动商品的数量'
    " ?4 T0 w. o) m( E
  6.     );
    1 W5 q. z( y. K+ `5 Z
  7.     INSERT INTO ta VALUES(100);
    4 w7 m. N( S3 O- h' @. _" x
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    : K5 T  \5 ?4 f) S& s
  9.      */
    / v! J3 p% u$ ^" O) D6 o1 f, p
  10.     + l- M" ^7 Z+ W8 f, X/ [
  11.     // 关闭错误报告2 m/ T$ b% J! a5 ]
  12.      error_reporting(0);
    4 N) b& `9 y, M3 `' |4 y! s

  13. ( {7 ~% F1 |4 d
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址  Y2 B: Q2 }1 p% q# b
  15.     $dbuser = 'root';            // mysql用户名
    * i/ T0 v4 X% ]1 [2 u) x& v3 Y! Y
  16.     $dbpass = 'root';          // mysql用户名密码0 v7 T" T1 P4 Y( W+ ^1 i
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    6 F* L: S. B. l( S
  18.     if(! $conn )& u- y4 x' p: O
  19.     {
    : H- F, I& h* j' A3 }8 t
  20.         die('连接失败: ' . mysqli_error($conn));/ H3 K8 w! S2 S4 f0 c
  21.     }
      y+ S. a# K, ^: C& r/ `) A
  22.     // 设置编码,防止中文乱码# F2 r! s. H; L: k) |% @
  23.     mysqli_query($conn , "set names utf8");/ d# N9 @6 ~$ G
  24.     mysqli_select_db( $conn, 'temp' );
    3 _8 m9 T3 q6 ?# q

  25. : |* A* q1 D5 s' S+ M8 Z# J: c& z
  26.     # php中的文件锁
    : X" V2 F1 l3 E  r' D
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    ; L: Z5 @! E" ~/ G
  28.     flock($fp, LOCK_EX);// 排他锁 & s- u7 u, e& H5 ]0 ^9 U
  29. 5 v3 G, ~9 u# H+ A
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); . U" e% ~0 n- b  \* G# f3 u0 Y, u
  31.     while($row = mysqli_fetch_assoc($retval))3 T+ O+ E* c( |9 A; k4 J
  32.     {
    " w! m4 E1 r5 }# g
  33.         $id =  $row['id'];7 o; m$ K4 F! O" u# M
  34.     }$ L) E: B) u( [7 |8 f" l1 p4 ?! p
  35.     ( C( g1 D! ^% L+ ~- S5 R. r
  36.     if($id > 0)   h  s6 R4 s- p6 O- v' m
  37.     {
    % ^" c( c0 C! Y* p
  38.         --$id; + _! P0 s7 `7 `0 V8 z) \) \
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); ! l- F* I; M" G; r* o$ i& N2 b
  40.     } 0 G7 }$ F+ `/ x+ z2 A/ l9 h0 E
  41.     # php的文件锁,释放锁
    ( u2 F! q' m/ G
  42.     flock($fp, LOCK_UN); ' ?/ X, M2 y4 o6 n+ h
  43.     fclose($fp);
    $ ~# Z* T* |( v) q
  44. ) m4 s# f% I7 V3 Y+ C" n  J
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    & r& `8 b: v5 ^; J# Y; O
  46.     // while($row = mysqli_fetch_assoc($res))
    4 u8 Q* ?2 p  h9 s
  47.     // {
    + P# `6 K. e: C
  48.     //     $id = $row['id'];
    1 r7 \7 J; N* a: A* u3 y4 C4 Y
  49.     // }  W( D. c" M+ {& @3 f
  50.     // echo $id;
复制代码

2 p2 ]& e& I# I/ {- M9 a  F1 h& w: @+ Q. C1 Z
抢券活动实例:
  1. public function envelopeSnatching(){7 |4 O2 Z4 p% O! m9 U
  2.         $lingqu = $_POST['type'];
    % ~1 T6 M9 D/ g* ^8 M
  3.         $uid=session('u_id');//用户id
    ! Q. F# h  g& |7 L8 n6 I
  4.         if(!$uid){
    9 S, d. P/ d& c! q/ u5 F
  5.             $data['msg']='您没登录,请先登录!';9 Y, ^7 u4 ]! Z0 |
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    , o* B" @! X3 Q. ]6 j$ y% U- ?& e
  7.             $data['msg']='不在活动时间内!';& K, i. B6 \9 i3 R5 O6 S( q
  8.         }else{. Z0 R) s; z- W. v/ U1 G
  9.             $hours=date('H');//当前小时数
    5 I' {# R' Z1 G; M
  10.             if($hours > '09' || $hours > '17'){- p; M$ S2 }, W  d6 P% S

  11. ( r7 T1 d( v( b9 }) @
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    1 t! p8 @( e5 S8 P6 D
  13.                     if($lingqu == 1){0 g5 \- x( P# e* [8 E& R$ X/ Z
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过+ F3 b4 T0 E5 Y* v; B
  15.                         if($hours > '09'){5 [. j' V5 D% o! @8 ^
  16.                             $num=mt_rand(25,28);//优惠券金额7 n+ p, n8 r4 C3 V
  17.                             $id=1;9 l( ~1 t0 ]3 U% A; m/ I7 W: v
  18.                         }& m" K: x+ I  D8 g3 a) W
  19.                     }else if($lingqu == 2){2 |, f. j6 {; ?. G
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    % S# ]+ v. ]- y9 ?3 l# E; a; s- h
  21.                         if($hours > '17'){" G1 n) h& P( X2 J0 H* V2 B
  22.                             $num=mt_rand(50,55);//优惠券金额
    : C9 Q" |# p& i' n# @. H
  23.                             $id=2;
    ' l% d7 s% |4 v/ n) _- o- e% G( B: B0 W
  24.                         }
    3 E1 C) Z& I1 D$ F
  25.                     }
    + u2 m, _. |5 r& Q7 m: ?7 n3 o' L/ z
  26.                     if(!$id){
    ! z- O' E- z8 V1 z) {
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    / f5 N8 f' K9 s# w) R
  28.                     }else{: q, ^/ E! `4 F, T
  29.                         if($is_lingqu){* ?/ n7 A. @" G+ x, G
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';5 D, n  S# a5 }; N. X% \6 |1 y
  31.                         }else{" w' a9 m; ^: P, T6 D
  32.                             //锁表
    : w, Q, |! S5 f4 e% m( M; D* x
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    9 p0 I0 q& P, A/ G
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    4 ?6 {7 S" Z& \" y
  35.                             if($active > 0){' R7 p2 F$ d6 i
  36.                                 //开启事务
    1 p. n* S- l% A1 a4 b4 d$ Q
  37.                                 M()->execute('start transaction');
    ! E$ [1 v9 V# Q* [/ d
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));5 t8 u) g9 _, h& n9 U8 S- O, R
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    0 H% D; a* a5 z- T
  40.                                 $members_preferential    =    M('members_preferential');
    $ K+ ?2 M8 N3 R  |9 @* c# C6 Z  Y
  41.                                 //对应投资金额,* _5 m9 K3 C2 O7 K
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));8 [# @& o+ R. D0 \1 J
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
      [. C! Y: {4 {" ^% E1 D
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    3 K& Z; x) M( m) a' Z( u  b
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券. ?3 r7 p" `7 g" o' z+ l- K5 x. v& W
  46.                                 if($save && $add && $add2){
    3 X, Z5 j) b# w/ m& X
  47.                                     //事务提交! B: U9 d5 k) m3 @
  48.                                     M()->execute('commit');
    , L7 |2 c! ~& l# F& Q
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    % N6 J( w; t4 D: N
  50.                                 }else{
    % H, t3 W& |7 Z1 Q/ s* I, I
  51.                                     //回滚( R6 M: s2 u4 f$ K6 X2 H+ q
  52.                                     M()->execute('rollback');
    ; Y9 d  G5 h  C, t) v
  53.                                     $data['msg']='未知错误!';
    + Q& C6 q' J8 b' z+ w9 U, f
  54.                                 }: U3 A) i/ P0 G# }! w
  55.                             }else{
    % H7 N9 R) X/ w  J" t
  56.                                 $data['msg']='红包已领完,你来晚了!';1 K# ?9 P/ ~8 ?; G" A# S( e' F
  57.                             }' P! v$ ~6 o  G" j/ N4 n& F" N/ O
  58.                             M()->execute('UNLOCK TABLES');. L/ s& j/ X/ P5 b+ P
  59.                         }
    6 N( j$ ^) @' \
  60.                     }
    # `1 j8 D( B8 E- u0 q% n# N" \  z
  61.                 }else{) S6 I+ x- b& ?- k# m
  62.                     $data['msg']='非法操作!';/ ~1 t4 U- Y' W" D0 n+ h
  63.                 }; z7 y' a( C) S6 o
  64.             }else{: {2 S% D/ ?1 r9 r! C! U3 x( M
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';" ]) O, f9 j) G, u. k
  66.             }
    - b. `' T; X+ @1 `, Z( t
  67.         }4 A8 V4 I0 m/ W, S8 ^
  68.         exit(json_encode($data));% S% I2 w7 G6 F: {% @
  69.     }
复制代码

9 G& h5 c2 ^5 H; K* W- Z
7 F( p/ ^  p1 f/ L& s1 N
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 22:32 , Processed in 0.053752 second(s), 21 queries .

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