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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 5742|回复: 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://请求的脚本
复制代码
2 ^0 \- S2 d% A/ J; `( G
Mysql中的锁语法:
; K' w, V# d8 w8 D: z3 vLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】) _( b$ v/ p( m# D% O% h% V
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
6 Q+ j, [, f% J9 s0 MWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞8 U3 q# C2 i0 V
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
1 a& r. l5 b( f* k: T" h/ B文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。/ f' Y& [" c/ `# {3 T) k9 M
测试时,有个文件就行,叫什么名无所谓
总结:& r- z  S8 g( Y. C; Q" ^' i# Y
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:+ Q: a. L* U! _. R6 Z4 m; j
1. 高并发下单时,减库存量时要加锁
" {- I/ _$ X( A+ g% M* J! D) {2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    - R8 W* r2 c3 a* w* q; M
  2.     模拟秒杀活动-- 商品100件
    3 g; l7 S7 y' y# \1 A: z5 c" T
  3.     CREATE TABLE ta
    & A& u# `; l2 b6 A9 A9 B5 Y! t5 t; P
  4.     (
    ' c3 n5 d, j( u) c
  5.         id int comment '模拟100件活动商品的数量'3 `6 b5 b0 Q) T9 z, S5 U3 F
  6.     );  R. ^- @. X, t! ?7 {
  7.     INSERT INTO ta VALUES(100);7 p' T, Q4 ?1 o) _6 \7 G' D' ?
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件9 T1 o! [; s. Y
  9.      */ 2 W/ Q( k) B# C4 _
  10.     ; X( n# c9 C- n+ {: `, H0 d
  11.     // 关闭错误报告7 ~! F" q4 q! o; R& K+ D  m
  12.      error_reporting(0); $ g2 D1 s% B7 n

  13. + u! h( x/ l' v  r6 O! [* \& q( ?
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( d- {7 {9 v% F3 a. X1 c( ]0 s
  15.     $dbuser = 'root';            // mysql用户名
    + d& o$ w9 K9 [2 N" F' u
  16.     $dbpass = 'root';          // mysql用户名密码
    0 w7 u) Q9 A" l8 P& A7 i6 G7 @' P4 Q
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);1 e# t+ Z6 ]+ e4 x. s
  18.     if(! $conn )
    ; R. K$ T2 w9 Y) A4 |, [
  19.     {0 f0 O/ ~. ~. F. t4 S0 H
  20.         die('连接失败: ' . mysqli_error($conn));0 W7 o# [' \6 o& r& F& N
  21.     }
    5 r; }3 q6 x% ~6 W' m/ k) I8 [
  22.     // 设置编码,防止中文乱码
    ; Q' u! q3 [! u# o
  23.     mysqli_query($conn , "set names utf8");/ @5 N) {2 M. x3 |0 A
  24.     mysqli_select_db( $conn, 'temp' );
    ; X: l2 \: B% e& u4 P! v( y. F; M

  25. 3 _7 X. J8 F/ Z5 f' B: q
  26.     # mysql 锁 " a% [/ f2 D& w/ [+ }
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 8 X2 c0 e6 i: Z% R9 B" j2 z2 _
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); % K# Y, X7 G: s& G% Z% N3 D
  29.     $id = mysqli_result($rs, 0, 0);
    $ G' u  B4 X( R5 s
  30.     if($id > 0)
    $ z% A' E- x+ u5 X; a# u
  31.     {
    3 H4 i; o0 C( r" ?
  32.         --$id; - |. x. j3 L# q( i% R' P( K$ P
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    5 T- z7 g* I- I9 U* u7 ?
  34.     }
    2 i2 ?3 G9 S- i  O

  35. - L9 x% {7 }- g& D8 t# g8 u
  36.     # mysql 解锁 . R  a( d  L' U1 H+ v& f
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    " g7 s$ z5 ]% v9 [/ v& C9 w
  38.     //查询解锁后的id值
    / n: Z! j' [6 m. |/ p
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
      _" @: c, `' f- r# w
  40.     // while($row = mysqli_fetch_assoc($res))9 e9 M9 k! Y! z+ \& i* W1 m( A: A
  41.     // {2 D7 L6 F$ [8 G) D0 f* r
  42.     //     $id = $row['id'];8 z! K5 c3 _0 j6 J2 a0 n/ [/ @0 ?
  43.     // }
    & @2 h( Z7 j" i) ~
  44.     // echo $id;
复制代码

# L( X4 O4 q) H9 B! P5 Y8 Y- n4 `# W, ~0 x/ g" W& O- r& G. f/ C) ]1 ^# D

5 y3 y" J$ m* A% K8 m, i
PHP文件锁示例:
  1. /*
    ( X& z9 b- P1 u1 B) V
  2.     模拟秒杀活动-- 商品100件7 J7 U$ X- L' N& ~$ u$ w
  3.     CREATE TABLE ta  K' M. n9 p# r4 ^- E! w
  4.     (
    ) @% a6 f- E: f# K6 d' G7 D
  5.         id int comment '模拟100件活动商品的数量'
    & |2 {$ p) H+ r* R7 Q) m" x
  6.     );
      x2 I- h) f% e
  7.     INSERT INTO ta VALUES(100);
    & }9 @: d! {$ |" A
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    * q( T# x  r+ @1 t* e
  9.      */
    # R* a5 q) \  k! a3 [0 a
  10.     ! x: m& D) m4 W7 ^1 o9 f
  11.     // 关闭错误报告, p/ K( D2 p  P4 t- e9 z
  12.      error_reporting(0); # S; x1 i  @2 M" u

  13. 8 n, m; {! x' N( ~8 L/ `0 @- K9 W8 s
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ; @) T& Q( `* H) s' Z
  15.     $dbuser = 'root';            // mysql用户名
    % S* b4 D$ e/ A* g; D
  16.     $dbpass = 'root';          // mysql用户名密码
    ( q) y8 `5 w& C' I8 p8 ]
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    . P# R. y6 x% t' _
  18.     if(! $conn )
      p, y( ]6 w- c. l
  19.     {0 \3 @% v" s2 X! n! u" l
  20.         die('连接失败: ' . mysqli_error($conn));
    ) W2 p$ W* e  s# K
  21.     }5 u: N5 W  e- \# ^7 ~  O% K9 ~% ~
  22.     // 设置编码,防止中文乱码' V& f, h, l/ ?6 b: X
  23.     mysqli_query($conn , "set names utf8");/ a7 S4 j0 m5 D7 o$ i2 B
  24.     mysqli_select_db( $conn, 'temp' );
    ' H5 N1 T: x; o9 p
  25.   B* p: ?9 g4 [1 G/ a
  26.     # php中的文件锁 8 G* m( a  d" v9 |) ~
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 5 n: U5 M$ N1 Y
  28.     flock($fp, LOCK_EX);// 排他锁
    : \0 H, ^+ m' A, k& I5 Y
  29. ; x2 d; a' H; \/ s$ t( s6 W
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    1 e1 F- Q& A; _6 r0 K
  31.     while($row = mysqli_fetch_assoc($retval))9 B- A: b% E! M1 R3 l/ j
  32.     {
    : Y- _  Q! g5 \; Q  S* n" q
  33.         $id =  $row['id'];7 K8 U4 \0 O" y8 e
  34.     }7 s! ~+ V1 o, W, M8 g
  35.    
    ) t& x5 N$ u- G% Y$ Q9 M1 `
  36.     if($id > 0)
    9 k1 M5 [  S) `* }( d
  37.     { ; w( u; L. k3 N# q) q
  38.         --$id;
    , v. p4 Z8 f6 _* C4 ~
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    1 h" K4 M3 r/ ~$ K1 l
  40.     } $ X- w/ m! {3 b3 h! g$ a5 I
  41.     # php的文件锁,释放锁   y4 a9 q$ k' g1 U. H/ d
  42.     flock($fp, LOCK_UN);
    8 `" f8 I! v. {. v) v7 k
  43.     fclose($fp);
    : b$ h) y! M3 F6 ^& E& t
  44. # m! M7 A$ `5 {# d
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');- r& h, k0 j/ s* _5 Z
  46.     // while($row = mysqli_fetch_assoc($res)). d( ?6 ]2 Z) V) M# w& S
  47.     // {
    1 F" a3 U; [" H% x: o2 T
  48.     //     $id = $row['id'];4 {8 Q1 O  S) z: C! U: g
  49.     // }
    ! @$ U& t' }4 e( K$ N" D
  50.     // echo $id;
复制代码

4 v. E0 l2 ?- K
1 t- t5 @# ~2 s
抢券活动实例:
  1. public function envelopeSnatching(){
    ) O+ ?# n. h" G( s
  2.         $lingqu = $_POST['type'];; V3 W9 m0 B  M6 O" T- X
  3.         $uid=session('u_id');//用户id
    / }1 P" e+ t( d4 Z
  4.         if(!$uid){( M6 E1 }6 K5 u* i; R) Q# j& z
  5.             $data['msg']='您没登录,请先登录!';
    1 B' G. F9 s8 K/ ~" F( ?+ \3 A& j( T
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    - D( b5 m' E* B" |! M. n3 H# j
  7.             $data['msg']='不在活动时间内!';
    " ^$ H9 S$ d0 r  u
  8.         }else{
    , |3 m6 ~, h0 ^  j+ X% f0 E
  9.             $hours=date('H');//当前小时数
    $ O' _6 z- Z% ^3 g! ^+ V$ P6 t
  10.             if($hours > '09' || $hours > '17'){
    . F# L. n. J6 P& M: e  l0 L" |
  11. 5 S7 ]: d# h. A, e
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的. [, |, K7 m1 \5 u& F
  13.                     if($lingqu == 1){+ F' K7 E8 }; C% Q( w! e, s/ Q  W! L
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过  a$ }$ ]# B" [6 d. E) y2 R% x  o
  15.                         if($hours > '09'){
    0 d2 m" ^: i: l/ C2 ]% P& T+ U, O
  16.                             $num=mt_rand(25,28);//优惠券金额
    7 a4 H7 ?7 M& c" @, f: f2 N% Q
  17.                             $id=1;% I& ^2 K3 l; G/ L' i7 u
  18.                         }
    * R/ q  p  q* J0 O; \
  19.                     }else if($lingqu == 2){
    ( [+ m5 S' R; T1 @' S
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();5 C8 D! J- {/ J" R* I
  21.                         if($hours > '17'){
    % Q  E" a. O$ a) q5 s
  22.                             $num=mt_rand(50,55);//优惠券金额5 `- H: k4 H5 T# A# }/ B1 M
  23.                             $id=2;" {6 |0 u0 B) I" ?
  24.                         }
    ' s; ~2 x" l- ]6 x0 U9 U. r% a9 Y
  25.                     }
    " P) e9 V: p# ^
  26.                     if(!$id){) L3 S& n2 i, R# ]! `, ?; G
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    + {& @7 Z" s5 M% ^; d: U
  28.                     }else{
    # f! E6 ~9 d! o. W( i
  29.                         if($is_lingqu){+ U% C6 N5 U# Z6 M
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    ; Q: v5 X& l2 I$ w& z
  31.                         }else{
    $ x, @& A- [& w* B; @
  32.                             //锁表$ p  p5 q' s9 e. Y4 u; y# H
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');5 x8 c" N! G2 f# J
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    : F* g* O* ?) I3 D- v
  35.                             if($active > 0){# j; M+ S" g5 q7 j
  36.                                 //开启事务, N2 `/ L3 z+ O: _8 A& E- E; O# B
  37.                                 M()->execute('start transaction');( c; U2 O0 E& y! R
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    - c- ^- u2 D9 o1 a  @0 F7 n
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));) [) `( t$ \& Y0 j* m3 |
  40.                                 $members_preferential    =    M('members_preferential');' S; V; q3 m* w* |
  41.                                 //对应投资金额,
    / H: }% t0 A/ V; I' ?6 b6 y
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));; N; a8 O6 m; z; G% c0 H
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    0 X' p1 |3 @" k
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间6 t# }/ @- P4 B, X
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券, b% p) ]+ N# S; |
  46.                                 if($save && $add && $add2){  o5 T* ~! I5 N. k
  47.                                     //事务提交$ r+ l" T3 t# @3 J
  48.                                     M()->execute('commit');6 u. \5 `3 U1 w( n. \
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    % G1 ~' `- W% C( L5 _1 H
  50.                                 }else{; W( S: h. w) K, A4 u
  51.                                     //回滚8 [8 f- E* [$ @7 d8 s1 A1 m
  52.                                     M()->execute('rollback');3 K% J- G0 Y( t, J( X6 v
  53.                                     $data['msg']='未知错误!';
    & D* U* |/ T* b! X8 w0 `
  54.                                 }
    ! r& i/ h1 Z7 `: D5 v/ q! w
  55.                             }else{: ?5 v! {" S; C, [8 R$ p8 G1 q
  56.                                 $data['msg']='红包已领完,你来晚了!';. j* N/ A) }& d
  57.                             }# ~8 C5 P$ B6 q$ T( @. e
  58.                             M()->execute('UNLOCK TABLES');, v. r- g* d9 Q& H# `$ q
  59.                         }1 H5 d+ m" ^; c$ ]1 x
  60.                     }- W2 ]1 ?( M8 M
  61.                 }else{
    ; U! A/ y2 L) P+ ^4 S
  62.                     $data['msg']='非法操作!';
    % I$ ~7 g8 b' u
  63.                 }+ I+ P3 J8 v0 Z. M: a$ d8 l
  64.             }else{
    ( h! f$ e5 ~' W- n
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    0 Q6 M' d2 @' B5 r  h0 ~7 v6 }2 I6 z+ J
  66.             }, h3 z! |( ^! `) w
  67.         }* ?& O4 U7 @; s, X1 p: N
  68.         exit(json_encode($data));- u0 \; u/ f1 {9 ]" a8 r
  69.     }
复制代码

2 G& Z4 ^9 O+ G+ F# S. A; y
+ R- t3 X8 E' S6 ?2 M& x1 s
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 16:35 , Processed in 0.115395 second(s), 19 queries .

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