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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

' C" N- \' @( K  J+ [* g
Mysql中的锁语法:: |% _( j. H1 d
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
3 z3 b" J* Y1 a9 k$ P) b( S3 S  c/ L5 }UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表+ |( x/ q7 j: d
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞& g# X5 L1 ?8 W9 @0 T3 Y( G
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
8 u5 {7 W6 B9 G# p文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
' x7 Q  Z# R; N1 r- W测试时,有个文件就行,叫什么名无所谓
总结:# ?" |+ G, e  Y
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:: ~9 `$ A% Q1 n7 R" t$ ^2 J
1. 高并发下单时,减库存量时要加锁' S; S6 H9 E+ C5 x& X& D" Z: \, _) C1 \
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    : H  {' B/ r, h8 c! j
  2.     模拟秒杀活动-- 商品100件( M9 ^4 ?, U3 M8 e+ c! z
  3.     CREATE TABLE ta
    ! u/ Q) F, C& k4 K5 y
  4.     (
    ' X/ N' Y- o: d' K# n0 [
  5.         id int comment '模拟100件活动商品的数量'2 b# G) M1 x7 _  t5 T- {
  6.     );
    5 u& z/ Q  E/ s( ~. g5 _0 a
  7.     INSERT INTO ta VALUES(100);7 U  o/ x+ _% E& ]1 O
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件- v3 m8 ^& m2 ~3 ]1 Z2 ]2 E" i
  9.      */ 6 E" [9 t. q% E5 U
  10.    
    % g% \8 I% u# A! |
  11.     // 关闭错误报告/ z8 y* M! E# v2 @
  12.      error_reporting(0);
    0 g0 i. _( R" |( B. q) I* i
  13.   \, u# A5 L. q: k: o( {
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    & w/ y, W2 @& Y& o9 K
  15.     $dbuser = 'root';            // mysql用户名
    9 s0 K! w: Z6 N% I
  16.     $dbpass = 'root';          // mysql用户名密码) ?/ D: c- |, F8 o$ Z
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    ! h; i  _9 Z; M5 ~( ~9 b
  18.     if(! $conn )
    0 X5 i! n1 @; P$ Z4 x
  19.     {/ Q. A7 \/ w2 [1 E
  20.         die('连接失败: ' . mysqli_error($conn));; r( V7 Z6 e8 E2 G
  21.     }
    1 Q- V8 }% K+ n3 b# e
  22.     // 设置编码,防止中文乱码; x* r0 G4 v  h
  23.     mysqli_query($conn , "set names utf8");
    8 Q( \% p( |1 Z! u6 F' |/ }5 H
  24.     mysqli_select_db( $conn, 'temp' );
    9 m! J3 F: C0 w8 K. b
  25. , ?* }% B  C& h5 G# b
  26.     # mysql 锁
    % J% F5 P) e- G0 H1 N  f& U
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    8 A) k& w. M7 w7 Q+ X2 t; n
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 9 w3 }& F% C7 p, f1 w+ K
  29.     $id = mysqli_result($rs, 0, 0); 7 L5 s6 _6 N* V
  30.     if($id > 0)
    & N, Q: ~8 i+ D0 U3 \
  31.     {
    + i! t% y! y# D+ t/ C
  32.         --$id; - s5 D, O# l, T8 Y
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 1 W, [' t- ?3 {$ U: J6 F  ~
  34.     }   }5 n" _+ s& D

  35. 8 \: f+ N$ G- @7 x
  36.     # mysql 解锁
    ( m4 ~" j( j: i" q/ ~. f% y
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    " K7 Q9 e! r% d' H* D
  38.     //查询解锁后的id值. Z9 [' O7 D. x, R) E
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');1 _" l" O) g. o' R) Q. O6 D
  40.     // while($row = mysqli_fetch_assoc($res))$ L) h; U8 a, k9 S( r8 \
  41.     // {% v" _. N7 W; @1 @9 i/ I- f; `
  42.     //     $id = $row['id'];7 N8 j9 B- B: j! T5 T1 t: {
  43.     // }
    # `* m1 |6 `+ Z/ S, \0 g# a6 B
  44.     // echo $id;
复制代码
6 W( O' u5 m  _6 T8 ~6 M

+ k2 k( x0 M. O/ s4 M1 k1 e
8 R) S& S3 P2 [% i  J1 h# j; |
PHP文件锁示例:
  1. /*
    8 r, y/ s% S2 _* M( a" f/ ?. N
  2.     模拟秒杀活动-- 商品100件
    ) P. X- E; x. `
  3.     CREATE TABLE ta6 [5 @- f8 s0 n4 ]* ]7 I
  4.     (
    ' A: @& @! k- R+ W5 d/ M
  5.         id int comment '模拟100件活动商品的数量', T; W( ]8 ~4 P/ ?  j' s
  6.     );! o3 B" i2 D* t6 z3 |  F% d, S
  7.     INSERT INTO ta VALUES(100);
    ! b8 d# T3 ]* e3 p/ j2 z6 b6 V
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件$ u# ]5 V1 Y- B. y
  9.      */
      A: W# G* A' A" H8 Y1 R9 G
  10.    
    " u9 [. k% e6 |2 \- }& ]. ^% k
  11.     // 关闭错误报告
    7 V  A& j% C  `# s( S
  12.      error_reporting(0); , I$ W: G& |8 F+ l' L
  13. 4 T$ b+ Q0 L0 g( i
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    " g& y' R  m6 ]* X4 y
  15.     $dbuser = 'root';            // mysql用户名
    ! Y0 s" _/ s2 y: F) _  ]6 d+ z) u
  16.     $dbpass = 'root';          // mysql用户名密码7 V& N2 Z- N# H- H- u5 K8 V* s
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    6 g2 B1 g" A0 e
  18.     if(! $conn )
    % ~' C# `" \8 k* f1 D, g" B
  19.     {  L) S% J( Q( o2 l9 @5 b7 ^+ h
  20.         die('连接失败: ' . mysqli_error($conn));
    2 n0 J( M; h7 U3 e) R8 p! A
  21.     }
    % o: m- }3 H/ K3 J/ Z
  22.     // 设置编码,防止中文乱码; q# ^3 D/ ^: M; ~  Z% P% j( z8 p/ U
  23.     mysqli_query($conn , "set names utf8");8 b4 Y4 U3 l2 F' A$ r
  24.     mysqli_select_db( $conn, 'temp' ); 8 F5 t( [( ^! G& O

  25. ; {8 ~- s; Q: A, M' r
  26.     # php中的文件锁 2 e4 P( {3 |6 g0 G9 I* N) Y: J  Y
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    * Y. }5 a  b# L' G! Z
  28.     flock($fp, LOCK_EX);// 排他锁 $ q0 P! L; F* r/ L) A

  29. $ V: ]% z  g/ i0 k
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    ' i( k+ o* t3 V3 j# `! V# S
  31.     while($row = mysqli_fetch_assoc($retval))2 b3 H0 I- L  Y# \
  32.     {
    7 g, I  Y4 N" {1 K* w1 @* u
  33.         $id =  $row['id'];% X' k$ S  g: F( G
  34.     }
    ) |1 r+ ^$ y4 h+ Q
  35.     9 z, n6 B. Q) q/ W4 }( ^* G
  36.     if($id > 0)
    : W! h( M4 i' ^1 k! h# x7 ]6 _
  37.     { 1 o4 n0 C' m. s, f9 I* o  n0 W
  38.         --$id; ! N2 C; _; _1 U; ?- c0 c5 f
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    3 j) m! D1 I/ D% `; F( x1 l6 h
  40.     }
    * q$ W3 q' t* x: _1 z
  41.     # php的文件锁,释放锁 ; i2 p. b  a& s2 J& W: T1 w
  42.     flock($fp, LOCK_UN);
    " o  f0 [' R% H' k: r
  43.     fclose($fp);3 e: }& a  j9 ^; V, Z$ O
  44. ) H; P5 W. k$ C) R1 o: d  s4 F9 r
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');4 A9 G- ?5 h" Z5 S; F7 j8 p+ Q
  46.     // while($row = mysqli_fetch_assoc($res))2 _2 L0 y, W4 Z$ m1 B7 ?' c$ T0 n
  47.     // {3 i6 q4 E0 O/ k* I& C
  48.     //     $id = $row['id'];
    6 X+ l( @7 @4 C0 e2 }+ j) c
  49.     // }
    4 ^9 S( @. Y0 m) W
  50.     // echo $id;
复制代码
- Y7 E+ u6 c3 S" A/ q1 `% \

0 T  p. P, a2 \( ^4 \
抢券活动实例:
  1. public function envelopeSnatching(){; V5 W2 ^7 ?& K/ I- s
  2.         $lingqu = $_POST['type'];
    & i+ ~6 r) p- h/ o& M6 X6 j) ~
  3.         $uid=session('u_id');//用户id4 ~/ |# ?9 Z6 T7 L1 L
  4.         if(!$uid){
    ( {4 O: q! t7 g6 a! z' G# B( s) l& K
  5.             $data['msg']='您没登录,请先登录!';; k% ?- s$ a' N6 G
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    ( R2 [) u1 U+ K8 q! i
  7.             $data['msg']='不在活动时间内!';
    7 v' \1 ^# L5 e! D6 \7 z
  8.         }else{! G$ o3 [  g- W# Z  x0 C
  9.             $hours=date('H');//当前小时数
    1 W) ~& f- f& D5 i; ~
  10.             if($hours > '09' || $hours > '17'){
    7 P6 r' k0 _& u- A. U

  11. ! `1 f* L1 R) ]
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    ' M9 }6 K2 n1 @7 z5 L: v* t( ?
  13.                     if($lingqu == 1){* ^; O' \/ [! p+ q
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过0 t  X6 N; @5 Z8 W6 R# N  [8 ]
  15.                         if($hours > '09'){" i+ o' ?( |! n
  16.                             $num=mt_rand(25,28);//优惠券金额
    ) \6 H% Y7 Q7 k7 x8 u
  17.                             $id=1;5 h: @5 s* G4 T. K
  18.                         }4 D9 p0 m% }* @/ M
  19.                     }else if($lingqu == 2){1 e6 F: y- D3 P8 \) J
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    5 x: I+ z- l) M  c& c
  21.                         if($hours > '17'){% m1 g; ?5 R& q' ~$ H; p$ j
  22.                             $num=mt_rand(50,55);//优惠券金额
    ) l5 g: n! z4 U* N
  23.                             $id=2;
    , l: \$ Z, H$ u5 O/ A' v% U% H
  24.                         }% _: f7 \' \( \6 V. v
  25.                     }# k% i  g$ A8 l3 H9 [0 d- B
  26.                     if(!$id){
    * e( d/ C( v0 M8 [& `, ^
  27.                         $data['msg']='时间还没到,晚点再来吧。';1 Q# ~8 I: V& R  W8 Y! Q4 H% n+ c& p
  28.                     }else{
    ! k$ o6 m! A1 n3 E8 o1 o
  29.                         if($is_lingqu){
    1 G( F7 Q8 e& G% M) I3 c9 i: N6 x
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    - R  u% e9 D: ]! _6 x! T4 |2 `
  31.                         }else{
    % n+ }$ F: `4 e, A
  32.                             //锁表
    1 R0 G0 N. q) X1 r
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    / z' n$ v# N9 v% `, j6 {
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();7 y: c5 C1 u! s# R4 i; V
  35.                             if($active > 0){3 S, a9 F0 N; g4 W/ S% m
  36.                                 //开启事务
    , a4 G6 `* F6 c$ |8 ]) b! F
  37.                                 M()->execute('start transaction');
    & n2 H) X* z' l
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    % d/ m2 s0 e9 e1 c7 U/ ?5 ]
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    + @7 k& T* R' y2 B
  40.                                 $members_preferential    =    M('members_preferential');
      z$ s: Y) H  K: J# i
  41.                                 //对应投资金额,
    # R5 U9 R9 p6 w5 r6 i- \
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));0 _. [% P# W3 E, K
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');' i" }8 p, s2 m; s
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间1 i% o$ w* K/ Q5 k+ f- j! k+ @
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券+ T* K3 x; c" A& j
  46.                                 if($save && $add && $add2){/ p+ B0 {$ N  G8 ?5 x- T, [+ W# }, C- b  s
  47.                                     //事务提交
    ( v- z) s7 J! R& A5 t
  48.                                     M()->execute('commit');1 O4 n+ b; F! [1 T% N
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    " f* M: X/ f+ P4 M1 W4 Z% G! U
  50.                                 }else{
    & g% A- d# Q! K, L- M7 o" ?  u; x2 c/ a9 ]
  51.                                     //回滚# T; W: \- M: z- r
  52.                                     M()->execute('rollback');
    $ ~# a* U& l; [. u3 v7 L& ]' j- c
  53.                                     $data['msg']='未知错误!';
      a0 }) k+ b9 E- D9 Z0 ~
  54.                                 }0 n, l6 L" g% H" u
  55.                             }else{
    / q( e0 m3 Y/ {  Q- c8 \5 D
  56.                                 $data['msg']='红包已领完,你来晚了!';
    4 p/ s) i  j4 ^2 J9 l- i
  57.                             }5 a6 w4 W5 g$ U; L$ X9 L& W' F  G$ f
  58.                             M()->execute('UNLOCK TABLES');
    ) }4 ~0 t: {$ u5 R) y( q( \& X
  59.                         }9 [' B! \1 Z5 J
  60.                     }# ?* B0 w; C: I6 ]! w
  61.                 }else{
    ' \" x5 p; M9 o7 f( B. \2 L8 b1 ^
  62.                     $data['msg']='非法操作!';
    9 {; e" O. u4 Q* ?$ ^# K0 R. I1 f3 `
  63.                 }# Y7 q& Q+ K' m5 c: Z
  64.             }else{7 F: F6 i1 N( Q( c- r3 ~- V
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    # ^) x3 ^5 K* @% B' s- o/ F# N, U! b
  66.             }
    3 {& c) s. v* H  R! B
  67.         }
    * R1 Y, j' o, F
  68.         exit(json_encode($data));
    $ L6 o* ]+ `- [
  69.     }
复制代码
, |  d. b9 N3 N; M3 }
' f' y; c, k3 @3 x0 `8 q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 22:26 , Processed in 0.064940 second(s), 19 queries .

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