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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

8 g. D5 P6 S% _2 b
Mysql中的锁语法:
$ C! Y0 M& {6 l/ L" X8 xLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
' b2 \) {& J2 Q8 vUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表1 ~: a6 Z8 R: O8 x
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
. r& L  b3 Y( P$ d3 u注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
  z# F+ ?+ v, B+ b% E- |$ t文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
% A0 R5 x' `- }$ r+ ?测试时,有个文件就行,叫什么名无所谓
总结:4 D% w$ l  `/ O: w, E
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:. L$ W  P8 M! i/ C6 j; B
1. 高并发下单时,减库存量时要加锁! T$ s2 ~9 T) G+ X- k4 A* g
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*& `# q- o3 S( }3 [8 X1 T" _
  2.     模拟秒杀活动-- 商品100件
      k% r6 @. o- H
  3.     CREATE TABLE ta
    9 D0 r& M# r; b5 |- q+ W
  4.     (% i  X& O2 w1 w- Y+ Y! t; P  @" b
  5.         id int comment '模拟100件活动商品的数量'$ }  T; ?0 X# J
  6.     );
    ; K! R: T6 ~' `0 u
  7.     INSERT INTO ta VALUES(100);
    ! k( ?, h6 {! }
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件! n- J* n  B' G# W
  9.      */ # S, ]: O8 N; m2 z
  10.     3 a: n) Y+ r& H: r2 c5 h  @
  11.     // 关闭错误报告( b( s' o2 t% t/ s- j- M/ i
  12.      error_reporting(0); ( G# `3 J9 o+ |9 g9 C
  13. ! J$ K' J$ |  m! S- t
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    0 A! F  \+ `4 ^8 e* \  v. N2 \" m: f
  15.     $dbuser = 'root';            // mysql用户名
    : l) }: H- K' F
  16.     $dbpass = 'root';          // mysql用户名密码
    ) D! W+ b1 [% ~
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);( c0 X7 b! |5 g0 Y4 S2 ^
  18.     if(! $conn )4 @, j  v& i0 f9 e$ l- ^
  19.     {; j7 d9 Q5 k# J7 w7 T) S
  20.         die('连接失败: ' . mysqli_error($conn));
    * y$ R3 w4 Q& k# W+ x( ?
  21.     }  d6 @6 B& Y) P) J3 t7 T
  22.     // 设置编码,防止中文乱码
    ) w$ l9 Z6 \5 r* F" f+ P
  23.     mysqli_query($conn , "set names utf8");
    + q! [3 ^4 q, ~$ z
  24.     mysqli_select_db( $conn, 'temp' );
    6 o9 {0 Z) a7 Y: ^( f. F& K- A

  25. , l7 @3 B7 e+ Z; q* x  R
  26.     # mysql 锁 , k( D9 r; _. B" x2 y- T: O
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 " e( [' B( H' D- K3 T3 ~* p
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 0 ]& `8 Y" z" O( q
  29.     $id = mysqli_result($rs, 0, 0); ' X5 S; p) A* w7 e/ G  R
  30.     if($id > 0) % t* k% r- j7 j& ^/ i9 H7 N) ]
  31.     {
    4 h3 ~9 O0 e3 V) Q5 N9 ~
  32.         --$id; 5 L5 ^* I$ x6 S1 ~) l4 F, m/ v
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    & _; u/ R7 w; \% T( o7 g
  34.     } / B3 d$ p8 t4 r: w
  35. ' O  R; b: f( h0 C8 e( m6 K' M
  36.     # mysql 解锁 ( w# U' N8 c4 [0 ^  L1 `
  37.     mysqli_query($conn , 'UNLOCK TABLES');0 X, v) t. P$ t/ Z. U
  38.     //查询解锁后的id值
    1 k% G1 Z2 v) i  G+ B. |
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
      s' f* X8 Z. E4 K. R; Z$ z, W* L
  40.     // while($row = mysqli_fetch_assoc($res))
      u4 v/ W) r2 N
  41.     // {
    ! U3 ]# V$ H+ g
  42.     //     $id = $row['id'];
    4 v) A- S/ w: N! T2 J6 R5 i+ h& J* X
  43.     // }  s2 v- x0 r% Z
  44.     // echo $id;
复制代码

( m* K& g6 Y2 g5 Z3 p& B) g9 \9 U8 B, m
/ Z& k% b+ w4 Z+ T6 D+ |" w/ C( c1 D
PHP文件锁示例:
  1. /*
    7 Z8 ^4 C1 i. @# p) I; I9 Z9 Z
  2.     模拟秒杀活动-- 商品100件
    ) U! s, h& [/ c  J
  3.     CREATE TABLE ta
    " S/ I9 Q9 V( X% Y
  4.     (% G/ J. J) F- B
  5.         id int comment '模拟100件活动商品的数量'
    1 d0 L+ t! j$ j
  6.     );
    ; b6 g, @- N. `7 x$ ^  }
  7.     INSERT INTO ta VALUES(100);
    & p( U  g! {  v6 u2 J9 A
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
      _% `  u. \% O
  9.      */
    9 _) o8 C6 ]% k, `6 w& A6 `
  10.    
    4 ?" r2 j4 E4 x5 f9 n
  11.     // 关闭错误报告
    $ n6 i6 l" E! {" [
  12.      error_reporting(0); / x: G$ g6 k: @- {5 A8 z2 z
  13. ! J2 @3 y& B. E( R5 J) R& q& j
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址& k( x/ ]# c4 I( J! u/ W8 S. a
  15.     $dbuser = 'root';            // mysql用户名
    4 h, h0 J2 `0 W7 ^+ W% M
  16.     $dbpass = 'root';          // mysql用户名密码. Q$ J4 n1 P3 K# _  l
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);* T/ i- @; h9 g2 k
  18.     if(! $conn )) @, m% E) U# j0 A
  19.     {, j* A( V, v; q: M7 Q: F
  20.         die('连接失败: ' . mysqli_error($conn));" o7 I* o: p- @/ S  }
  21.     }
      p- `4 s, S6 f+ M' H% e* W3 t
  22.     // 设置编码,防止中文乱码* U. E/ m3 L  j* f7 N. G" u
  23.     mysqli_query($conn , "set names utf8");
    ' C+ c6 B* N7 X' F( y
  24.     mysqli_select_db( $conn, 'temp' ); 6 v  D0 G' e  \5 ?9 L: T
  25. - s! j+ g. b! I, N9 r
  26.     # php中的文件锁
    6 z/ i0 C' B: C$ N" G
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 : k7 r, J2 A6 J/ }5 ~
  28.     flock($fp, LOCK_EX);// 排他锁
      k* i6 Q  Q  F) ~* D

  29. " O' ]2 Z: c; b8 l9 p, I5 Y2 K
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    , A' C- `7 r7 t; K/ V" J
  31.     while($row = mysqli_fetch_assoc($retval))
    2 i! [( R" N; N) p7 Q
  32.     {
    & F- Z  Z1 T, n5 O! s
  33.         $id =  $row['id'];
    ; K& y6 E  e& t7 K
  34.     }
    - ?1 B; y1 i+ @7 j
  35.     + m5 R* J4 G8 e6 Q' j/ V7 K
  36.     if($id > 0)
    * v. T: j1 c2 ^9 Q8 G7 ^; }
  37.     {
    - ], q9 k* [# [, J4 I) l
  38.         --$id;
    3 X* `. g4 {& H- z* m; W
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    . N6 e+ z$ r% O7 p/ D% M* W
  40.     }
    * x; v& b6 m+ i8 _
  41.     # php的文件锁,释放锁 ' t- {1 v( ^: R4 A, O
  42.     flock($fp, LOCK_UN); ) I5 F) L) m/ H: F& y' J) @
  43.     fclose($fp);
    : U0 Y1 z7 m% t) T& w3 y% M
  44. . }9 ?5 H0 K% d" u: n8 i
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');9 v3 [* h) a: j
  46.     // while($row = mysqli_fetch_assoc($res))- U# n& M7 c+ r5 g: k
  47.     // {4 F; ], ^9 R. ?. }- }( ^
  48.     //     $id = $row['id'];
    , W4 {$ M, x- z( w$ }( S; q
  49.     // }( B$ r, o, ~# T5 I- x1 F3 W
  50.     // echo $id;
复制代码

/ p) C0 w* u  [; p' R$ V  C, d; `% c! P: |& H
抢券活动实例:
  1. public function envelopeSnatching(){0 O9 T) U$ \4 L) [* L  l( \+ x: R
  2.         $lingqu = $_POST['type'];
    ) W1 U" j' U$ {% g
  3.         $uid=session('u_id');//用户id5 ^* n. F. a1 W8 y4 e! i
  4.         if(!$uid){
    " l7 G. w( v0 q
  5.             $data['msg']='您没登录,请先登录!';9 U' i! `4 S9 M1 s& T8 |/ z/ L: p3 P
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    6 a! B' H( ^0 g6 h0 q+ V4 d, r9 P3 l
  7.             $data['msg']='不在活动时间内!';. E4 |0 q# @* ]$ W
  8.         }else{
    - x5 h7 B3 M: ]$ N1 t7 |
  9.             $hours=date('H');//当前小时数
    # a1 {4 t3 x0 X7 `; s
  10.             if($hours > '09' || $hours > '17'){4 t: T/ o) x1 V. l9 ], {+ q2 {
  11. ) }$ R5 w6 b! E' y9 T: k: p. j) X
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    2 y1 t- [1 p4 Z$ X0 ~( C6 m
  13.                     if($lingqu == 1){
    # X! R) P6 K4 c  N
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过, N$ s  [+ _: G
  15.                         if($hours > '09'){
    8 q1 J* m/ `, B3 l2 V
  16.                             $num=mt_rand(25,28);//优惠券金额
    7 x+ n9 ]& P$ Y2 j0 S" m
  17.                             $id=1;0 z1 I4 g. s" H! I& b) y
  18.                         }
    6 h" i* J9 R. I9 N, x
  19.                     }else if($lingqu == 2){
    " L+ }, i( m$ Q% `' R
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    ! P. V/ X+ Y* c& q- B4 }  v  K% s
  21.                         if($hours > '17'){
    3 m- w) E! R3 O& f
  22.                             $num=mt_rand(50,55);//优惠券金额! D5 X: X3 n3 {' l, i
  23.                             $id=2;
    8 B% J. o6 Y- Q0 c, s" l' K  ^! I+ @
  24.                         }- l) N6 J% N2 W
  25.                     }' L3 O! k6 X4 ?  H! S% d; S
  26.                     if(!$id){
    * b( \3 Z4 l/ v, V+ R. f
  27.                         $data['msg']='时间还没到,晚点再来吧。';1 T! D2 }8 u. W; w' i$ z+ Z
  28.                     }else{
    * L9 D7 H# {: W% ?
  29.                         if($is_lingqu){
    ) x" z; M2 D; k9 [1 N( x
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';) |  i8 S3 O' ?: V  p1 g* l
  31.                         }else{
    ( u" t9 B) a9 k
  32.                             //锁表! Z4 K) A, X' G) V% r, A2 T( h/ Q
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');' N# q6 f( S6 x7 n! _
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    1 _6 D' |4 H) e/ M5 Z- P( ^4 ?
  35.                             if($active > 0){
    ; A7 Q. M! K- ]1 b4 y; `+ ?! E# {
  36.                                 //开启事务
    : Z# M9 Z7 h' ~! U, [
  37.                                 M()->execute('start transaction');/ @/ ^2 J# C+ [% M  }+ O
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    9 Q! G, I# F& a) p6 r. L$ K
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));  K( J  ?; p' x
  40.                                 $members_preferential    =    M('members_preferential');  O7 m- K) T: M3 K, u
  41.                                 //对应投资金额,9 e1 i1 n# o: F% e' a8 S* v/ L
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));1 a4 Y7 E, f/ F/ d# ^! ~* O9 @
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');  V* K0 z6 `, g' }+ M! h
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    / A9 t" E0 W2 P9 k5 G8 h3 t
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ' X* o& u) F0 S! \* P
  46.                                 if($save && $add && $add2){; a! h8 M$ ?/ Z7 p% ]# Y/ a, F' Y# F
  47.                                     //事务提交
    8 w* V  U! y( P4 l! w/ }
  48.                                     M()->execute('commit');
    , R* M1 T$ t4 O0 R* f9 ]7 t' m
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';, D3 b' o7 p4 s( f% W
  50.                                 }else{
    / f; c* m$ w: A( G2 m7 x. h9 W
  51.                                     //回滚  y, b5 O7 |: K# l, h
  52.                                     M()->execute('rollback');
    ( \( @( r2 k3 \4 t5 b  u& \
  53.                                     $data['msg']='未知错误!';5 b" Q+ O; l6 ?
  54.                                 }
    . z# h+ p8 |" P
  55.                             }else{
    2 |+ T$ Q2 |  }& j
  56.                                 $data['msg']='红包已领完,你来晚了!';5 h9 W9 ]% `' b7 G* G$ Q' r
  57.                             }; F* b- v' J6 t  ^9 w4 D* D2 N
  58.                             M()->execute('UNLOCK TABLES');
    8 H" ]" _. h9 d  n( x$ e  M
  59.                         }
    9 y6 `  k* q  C" V
  60.                     }! u" b; C# V4 P( p+ ~; V1 p1 R
  61.                 }else{' G$ x: |5 q1 D9 |2 l. A
  62.                     $data['msg']='非法操作!';. }! f6 w: }& V9 V
  63.                 }8 ~6 ]: U0 w( Q+ W) R4 V5 u
  64.             }else{
    2 c& P! R: p' D
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';! r- p7 S3 i3 L; J
  66.             }
    % k, ?1 B1 x0 t2 V( l4 @
  67.         }, q3 O) p! s* n, }! m# P* m/ W
  68.         exit(json_encode($data));
    $ u+ I2 z; x) A  b& _/ ]
  69.     }
复制代码

* a( m% N) W6 \2 ]
2 R- c4 S/ P. ?  e' l: z, z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-22 04:10 , Processed in 0.072230 second(s), 19 queries .

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