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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

) E" x+ V$ |' m& P
Mysql中的锁语法:2 I$ H- ?' @" v! o
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】! x- O: L( n0 D! A# U
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表0 r$ N- [% J! P* W
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
- B' h3 P; M* m% ?9 Y* Y- Q* W1 p注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
1 l% _/ b$ m0 t8 u文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。3 C3 b5 t: A1 H# ^; d& M7 M
测试时,有个文件就行,叫什么名无所谓
总结:
7 O* I' R6 \, d, }- {$ ?/ U项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
9 v! H# k( b3 W- q4 f1. 高并发下单时,减库存量时要加锁2 D* q: U3 r  T
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*+ \2 v' f# f3 L, |- `, z( m
  2.     模拟秒杀活动-- 商品100件! m4 ^& `; R3 i% H. @' q9 J
  3.     CREATE TABLE ta7 R1 l& r1 Y0 E
  4.     (  R  m7 j# C* u' X
  5.         id int comment '模拟100件活动商品的数量'
    - F8 \# R3 m2 J$ {/ r/ `
  6.     );
    , q: C( v1 d+ G! S8 S' p  ^
  7.     INSERT INTO ta VALUES(100);" q' P# C: d' _$ y
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件/ P% |& A5 T% s% ~& T% `* o
  9.      */ 1 G: [/ u; ^8 E3 C, c! w) M
  10.     6 D6 R, V$ t7 q# b7 \& V* s  l# g" d7 E
  11.     // 关闭错误报告
    # ]" c" o# a* `( q* Y3 _" Y: E
  12.      error_reporting(0);
    ( M* F# J; a* b) M- p# N

  13. & a! t: Y% w+ E: x- |
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    4 p5 r- N8 s+ G* i: ?8 V
  15.     $dbuser = 'root';            // mysql用户名$ y! s3 |9 a" u' j
  16.     $dbpass = 'root';          // mysql用户名密码% \+ l4 J0 ~" r/ e
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    * b* s0 [% R' ^% x7 _* c: c% W' l
  18.     if(! $conn )
    7 F0 V, @4 z8 ~% l
  19.     {
    $ P8 B% d- B- J* `
  20.         die('连接失败: ' . mysqli_error($conn));
    " a# i5 D; W4 ]& z3 S# k+ D- R
  21.     }
    & W. Y, c; i# ?5 W& L, s* {
  22.     // 设置编码,防止中文乱码
    ; G* S/ c! I, e( P( _: ~. @6 J
  23.     mysqli_query($conn , "set names utf8");! D: L+ j: }5 B. c; j( [
  24.     mysqli_select_db( $conn, 'temp' );
    % h! N3 d7 N5 E. i5 G8 `
  25. & \) L/ J* i  P$ L/ c! ]# i- W0 |
  26.     # mysql 锁 2 R* {, D0 H# a" w3 i
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    7 h8 o# U+ R. _6 z
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 3 U* s! e  L1 h, |) r. j7 O
  29.     $id = mysqli_result($rs, 0, 0);
    ; |- f( v1 l! i; g9 ]/ ]- \: ?$ V$ Z
  30.     if($id > 0) 9 o; X8 B7 R/ h- |& A9 Q; N
  31.     {
    ; {5 I8 p; o4 B- J' u# S
  32.         --$id; ( m/ {$ m$ e1 p" i3 N
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 9 ~6 w* Z& r3 ^) U/ P, s! f% C
  34.     } 1 D; e8 t7 W. o, E* h, r
  35. 2 k  K/ F5 W  {5 r
  36.     # mysql 解锁 & }- a% ?& H- g. `, Q
  37.     mysqli_query($conn , 'UNLOCK TABLES');7 l* b; F+ Z- t8 M; J
  38.     //查询解锁后的id值
    & O9 S8 Y; j! W. e: `, V, @
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');/ z2 s4 u, u0 R- j3 ]
  40.     // while($row = mysqli_fetch_assoc($res))
    ( S/ Z0 B9 H  i7 H! h: O  U# Z
  41.     // {
    , ~* v' y; q4 B
  42.     //     $id = $row['id'];
    * z" i# D; d6 w, ]8 H3 Z- C
  43.     // }9 k) Z0 t0 m1 G6 }6 N7 m& b3 N7 D
  44.     // echo $id;
复制代码

+ {( g# G. B4 M9 i# j) x; |# G3 g# j  T$ M1 f

+ w. q0 F) {( Q" F1 j- G
PHP文件锁示例:
  1. /*  S1 {8 ~: q( h" Z4 c& P* U
  2.     模拟秒杀活动-- 商品100件  n+ t7 o* @& m
  3.     CREATE TABLE ta, |* ~4 @2 {8 w# D( |5 G
  4.     (+ o* D) L6 r+ z0 V" ^9 N1 ~
  5.         id int comment '模拟100件活动商品的数量'
    + f8 N" n7 B# X* j+ W$ M5 z1 t8 c8 I
  6.     );
    . S/ M7 t) L; r+ A4 L7 v
  7.     INSERT INTO ta VALUES(100);
    * |* C0 J0 |6 R2 ~$ Y. i+ P9 j
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件! T& {1 h" P9 O4 @" x6 t- R3 a
  9.      */ ' L8 S5 ]- f' [+ c4 {
  10.     * e! |" r$ o3 @
  11.     // 关闭错误报告
    ! R* I  |" t0 O' z9 H: {
  12.      error_reporting(0); ) G3 ~. W1 I" W& P6 W2 P( l: ]
  13. ; L, a* C' S6 f4 Z; r; R3 k
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址- A6 L/ {; V! F. v+ e
  15.     $dbuser = 'root';            // mysql用户名& j8 [& {: I; R4 w( m9 `
  16.     $dbpass = 'root';          // mysql用户名密码
    ( z- }* H$ J! D" {' h( @" p
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    " Y, a/ R! b$ S1 Y8 ^8 M
  18.     if(! $conn )( c0 X1 X2 Z5 ^$ f
  19.     {
    + ?: J6 o3 ?- Q2 @/ M7 Z
  20.         die('连接失败: ' . mysqli_error($conn));
    6 B2 ]; m" x# V& Z8 K
  21.     }/ g( W2 O3 q) S. G
  22.     // 设置编码,防止中文乱码
    3 A+ o2 ^4 h4 |9 T
  23.     mysqli_query($conn , "set names utf8");
    ! K& u9 P: G+ i" A: E6 i# |
  24.     mysqli_select_db( $conn, 'temp' );   }1 `5 x* Y# Y4 k+ B) w

  25. & J) A! T/ S1 A3 ~+ J" _/ N
  26.     # php中的文件锁 ; r: ?( r% L# q
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    ' K( m% x- W0 V1 u
  28.     flock($fp, LOCK_EX);// 排他锁
    * U* V4 l) x1 u" D
  29. 0 @  W# M1 Q# R- A3 X
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    $ z  v8 H; I5 t
  31.     while($row = mysqli_fetch_assoc($retval))
    ) e; r' [4 R% j9 |9 I
  32.     {
    5 q9 |2 m3 Z: Z) x
  33.         $id =  $row['id'];, c' R, _0 u- E; q, j
  34.     }
    ) e# \/ a; x) D2 y/ J& ^8 l; n+ ^
  35.     8 r3 c9 @9 v+ p7 r& U2 q
  36.     if($id > 0)
    8 [% H3 u) M; u9 o% P6 ^5 [$ R# h
  37.     { 0 [" D; y2 M" F& D
  38.         --$id; ) n0 F. O  ~5 B+ I/ [" r( L  W( B
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); : C  T8 z% `5 M; t3 E! ]
  40.     }
    1 r! a; Y9 S; }% T( B
  41.     # php的文件锁,释放锁 ( P4 u3 T, j0 W, Q0 I) o
  42.     flock($fp, LOCK_UN);
    5 e% m# k+ e0 m5 H
  43.     fclose($fp);% n! ]. v; L. y/ Q
  44. , M$ E+ ~% L5 u, M0 d- B
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');5 x9 k8 V7 Z2 w( j, c/ x4 l0 q
  46.     // while($row = mysqli_fetch_assoc($res))
    % Y* `. @6 A) @) [, b
  47.     // {
    0 t7 [# @- F# E8 a
  48.     //     $id = $row['id'];
    5 m% \3 A8 m' M
  49.     // }0 S" P' F( Z' ?- i
  50.     // echo $id;
复制代码

$ J3 _7 o! B# ^
& I/ L; X9 w1 [) F
抢券活动实例:
  1. public function envelopeSnatching(){1 G) j; X: k! u; a  c
  2.         $lingqu = $_POST['type'];
    ; l$ D7 F: |8 A
  3.         $uid=session('u_id');//用户id) ]6 p! Z0 P, ?
  4.         if(!$uid){
    2 d! b; q" x; J( w2 G* W7 O
  5.             $data['msg']='您没登录,请先登录!';; `4 O7 U3 F1 S3 j9 D
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    2 i; a$ h6 \# [9 y
  7.             $data['msg']='不在活动时间内!';8 `, ~; ?) w. W
  8.         }else{
    " }3 ?& N7 j* p: v  N8 o1 H
  9.             $hours=date('H');//当前小时数; ^( r* m1 M6 S$ O  f# P
  10.             if($hours > '09' || $hours > '17'){6 G  @# ?- V; K

  11. 2 W, C' h7 t$ u2 Y3 G/ X2 p
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的9 M  W0 }, Z4 p
  13.                     if($lingqu == 1){
      T5 x# j4 w9 v! K
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    6 L, W& i8 g0 v( |* [
  15.                         if($hours > '09'){
    ; Y9 y! `) A" ]
  16.                             $num=mt_rand(25,28);//优惠券金额
    1 g3 t1 H7 v' x9 e+ h( O' B9 x
  17.                             $id=1;9 z! y( c2 D. B1 c
  18.                         }
    0 V/ y, e: {$ X6 j; \
  19.                     }else if($lingqu == 2){
    5 g7 Z' G3 u" u4 h
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();; k- r: R4 g& V' |2 \& K9 M4 V' O
  21.                         if($hours > '17'){. u. @3 B( O5 H, z5 W
  22.                             $num=mt_rand(50,55);//优惠券金额% C6 i4 i7 x  N& L% J: `
  23.                             $id=2;) d2 P7 G! r7 T& b! r, |/ F
  24.                         }3 w! C+ q( L2 f( G& R- H' F
  25.                     }% N  X2 R5 q( J. o
  26.                     if(!$id){
    3 p" N4 b5 u* V5 D4 t( P* a4 @
  27.                         $data['msg']='时间还没到,晚点再来吧。';* e, D  }: B: y. z1 C
  28.                     }else{# g- r: N* S3 Z4 m* L
  29.                         if($is_lingqu){7 N, c; H% n% q6 y$ s
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    7 p1 S9 ?& f' H
  31.                         }else{8 L5 G9 h9 {! p
  32.                             //锁表
    4 X: p4 j/ u$ {1 Q" i6 `
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');9 ~  f0 A+ C5 Q! s+ n2 o* h* l+ Y
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    9 }* g& ?. i: U1 [0 D
  35.                             if($active > 0){
    + L8 H9 U/ L$ X/ z8 \5 |4 J
  36.                                 //开启事务" |5 }- b" e9 a% D
  37.                                 M()->execute('start transaction');2 `# n" @) M+ ^: U4 L+ w1 }
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    ) q) R& z1 m% }
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));, M) d+ m0 T" ?+ F0 U: x
  40.                                 $members_preferential    =    M('members_preferential');  ]- N5 A1 A( S: C: z
  41.                                 //对应投资金额,# {. R' ]' ~6 ]# G( N/ l; z
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    : o8 r) o4 Q& A6 o, f" Y$ {; H! ~
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');  C% u- U( V- `3 Z! \6 z
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间/ t2 c8 Z  C! x& C1 L
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券$ G8 b& |; _& E5 o
  46.                                 if($save && $add && $add2){
    # J$ Q1 `. v. y/ @  ^: h/ P
  47.                                     //事务提交- L5 U' O2 p4 l4 o9 Z0 }
  48.                                     M()->execute('commit');9 h7 ^) N- X, |8 k
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';1 w* }6 y! [% J, E4 Q+ s
  50.                                 }else{
    8 q* P9 `5 ^/ w5 D+ N! a
  51.                                     //回滚6 o! n+ g( O7 |! h8 X  B
  52.                                     M()->execute('rollback');1 i6 H9 u; U$ X* E% Q2 @# _
  53.                                     $data['msg']='未知错误!';% R. v1 d6 a% Q
  54.                                 }. k/ e" N3 c8 O- F
  55.                             }else{) ~* h9 i/ P( n; E* _
  56.                                 $data['msg']='红包已领完,你来晚了!';. @3 \/ i# i  N! X! D
  57.                             }" S6 K+ G* L. f/ [& }% P
  58.                             M()->execute('UNLOCK TABLES');
    ! T" H" O* Y- H, X5 r$ q$ j# Z
  59.                         }  K5 ?6 ]: h  Z  Z: B6 y
  60.                     }
    $ ]# @% ^' k6 E3 ^& t
  61.                 }else{
    # o1 s' s0 o3 ?9 }  t1 ?
  62.                     $data['msg']='非法操作!';7 p' J9 r4 U  e/ @( p- [
  63.                 }7 `7 |! D; f, h7 c, X0 t/ N; q% _) H& M
  64.             }else{
    6 q, A- }% P& h% y. c
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';. J& G0 Z0 W. q& q: M) e; F7 ~; |
  66.             }) Q! Q  `( t+ b# P" W8 Z3 r
  67.         }
    5 [$ u5 A0 t  c$ m' Y$ m
  68.         exit(json_encode($data));+ a* ^( M. z2 m4 s( t
  69.     }
复制代码

2 I8 e' J' B5 ~; |$ T7 |- l- z2 |7 {: [* j/ D) X' c, K1 a. H
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 08:21 , Processed in 0.057378 second(s), 20 queries .

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