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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8371|回复: 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://请求的脚本
复制代码
5 I* x; g6 ]1 Q3 S% C/ L( f' W
Mysql中的锁语法:' V  q1 N8 Y( g( F
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】# y) A7 x5 r3 s* P
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
* P! x8 f- f6 T4 X' h1 x8 tWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
" \5 |7 G0 p  ^0 {6 m. L注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
' l  W% l* x7 e) W4 @; H# [, `文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
) F. b$ O4 E9 i  W" U0 u5 |. f$ |测试时,有个文件就行,叫什么名无所谓
总结:- W. C' m5 [  s3 r' @  F- y8 J6 u  J
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
. M/ |6 v; w5 Q/ c1. 高并发下单时,减库存量时要加锁3 d3 X9 ~( C. R/ n8 f8 z
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    2 g! Z& q5 I  n9 p. [
  2.     模拟秒杀活动-- 商品100件# w# ^* b7 T/ G; {5 p( d
  3.     CREATE TABLE ta
    : ?1 N- X9 J" l1 ~9 Y& F6 U1 D% J# y
  4.     (
    0 s$ L; K' o6 D: }+ B' O
  5.         id int comment '模拟100件活动商品的数量'
    ( ?& f7 M; j8 b6 [, H' V
  6.     );2 o5 C6 r% n  s- l. ]0 [$ a. O0 J
  7.     INSERT INTO ta VALUES(100);
    6 ^# X, K+ u: R/ ^9 w- [8 ]
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    + @: ^! q- h3 ?9 F( D5 d+ A
  9.      */ 3 M3 R# l2 l* c5 P6 A, s) h! G
  10.    
    + ?4 w6 O( G7 C. {: z2 P
  11.     // 关闭错误报告
    + B/ g' a2 G9 I
  12.      error_reporting(0);
    - N1 M8 _: e7 }$ u8 b
  13. ; j: H7 J- l" o/ ^. w
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    % J8 f1 V7 |0 x* l* H8 }
  15.     $dbuser = 'root';            // mysql用户名6 h- H6 ~7 G/ e2 y/ U: J
  16.     $dbpass = 'root';          // mysql用户名密码
    % w. D7 K0 {$ C; k3 z$ r& @- m
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);2 W" ?4 @5 e- l  A3 E1 ^
  18.     if(! $conn )5 J5 X; n2 c" z9 @0 [# m/ Z
  19.     {9 p  K" p$ \; o- @9 C
  20.         die('连接失败: ' . mysqli_error($conn));. }/ k( E! z: u' C, ~! y
  21.     }
    2 X. m3 \$ K5 {. o7 `
  22.     // 设置编码,防止中文乱码
    : g- M, y% k: E, z/ h
  23.     mysqli_query($conn , "set names utf8");. e% \* o7 C% D6 b$ |
  24.     mysqli_select_db( $conn, 'temp' ); + ~* x; z) j( U8 a& |6 W9 @3 v$ ^/ K

  25. " |* n/ T2 z7 }9 W$ |- B: Q5 ]4 r- |
  26.     # mysql 锁
    ! n  \! p# o0 G' G' V8 {4 G, X
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 6 ?# R0 D! |8 U8 S. L! d
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    7 Q' ?% x% N) k8 @, I6 I7 R
  29.     $id = mysqli_result($rs, 0, 0);
    6 P+ q6 U/ e" j% w7 q
  30.     if($id > 0)
    # W6 ^% _" j7 @
  31.     {
    " ^. Q" T* o: z3 r$ D
  32.         --$id; 6 f9 H+ k4 x- _! T, B! k8 _
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); % j3 D. n- E& h) K/ u6 q: w- W" l9 v( Q
  34.     }
    9 F) }4 t1 M- Q
  35. ! K  k' i' t" O/ O  ^
  36.     # mysql 解锁   m. d" B. @7 ?: f; R6 U" L1 O
  37.     mysqli_query($conn , 'UNLOCK TABLES');' f4 v3 J; c. R+ w0 H
  38.     //查询解锁后的id值% r$ o+ j- _6 S. p4 y
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    2 t1 [' v+ L+ p( l# Q8 x
  40.     // while($row = mysqli_fetch_assoc($res))1 j) N2 h+ g3 B1 ]7 K4 X& C
  41.     // {
    1 U; z$ K& _2 y* \
  42.     //     $id = $row['id'];
    * w/ Q, L  a! r+ q
  43.     // }
    $ J, F0 C8 L; m, e' v
  44.     // echo $id;
复制代码

3 b9 q4 \5 A3 t* F
; s# ~( \7 }9 \: ]0 F9 N
8 `; q% X5 n" A( j4 P* y
PHP文件锁示例:
  1. /*
    2 K( X& a* D  c  t1 b3 K
  2.     模拟秒杀活动-- 商品100件" F4 C# Q% V, ]. m  ]" [
  3.     CREATE TABLE ta  ?. L; P& U" Q1 G' l8 u8 s
  4.     (
    ( W% S; T+ i( u' `
  5.         id int comment '模拟100件活动商品的数量'
    : \1 V3 G7 l% G. q7 h& o$ |7 N
  6.     );
    2 L6 r) g2 W! h% T# T0 N
  7.     INSERT INTO ta VALUES(100);2 N: a0 K! c- B* F- E* o% s) Y
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件% j& F2 S$ R. D
  9.      */ 8 ?. P4 E$ _) e9 E! L- T, p
  10.     * w! |- `/ d+ o: R3 k
  11.     // 关闭错误报告
    & |( m* ~# Z& [2 D  _# K
  12.      error_reporting(0);
    6 k- P# t+ y6 \" [7 O- l0 t4 y

  13. % [6 B1 Y9 P) E6 h9 I' N
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址+ Q8 P9 D/ ]( X7 m; U9 ]8 u
  15.     $dbuser = 'root';            // mysql用户名
    2 B- o4 ]& z' g( I3 s
  16.     $dbpass = 'root';          // mysql用户名密码; S1 j" }! I3 B/ \: J5 v
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);- ^* I7 e# C! w+ U4 n: v
  18.     if(! $conn )/ s4 K: y. v5 N; K3 s& p: H# Z
  19.     {  L7 E4 Y# B4 R' q% r$ V
  20.         die('连接失败: ' . mysqli_error($conn));" |4 L4 l# M. r. T" d( T7 ^8 m
  21.     }, K, F- H8 {6 `+ N" O
  22.     // 设置编码,防止中文乱码
    4 k0 u' @' ]  N  T, T' p5 y  N
  23.     mysqli_query($conn , "set names utf8");0 s' D6 H1 [$ r# A1 I
  24.     mysqli_select_db( $conn, 'temp' );
    1 R0 W% D& a/ U- ]" g( ?1 [6 K* Z

  25. * ^, t4 M. d/ `
  26.     # php中的文件锁 " Z( _. j& @8 k* B" E6 }
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    * k- y6 S2 N8 R
  28.     flock($fp, LOCK_EX);// 排他锁 0 f4 ~6 U% ^! j( o" E
  29. , d- U+ u( N; R, P
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    ; M' @7 o8 z3 i9 `6 g0 @+ s3 w
  31.     while($row = mysqli_fetch_assoc($retval))# L* @: k+ c* Q* s! @2 W
  32.     {
    ; w3 P' V1 g$ u7 t% Q
  33.         $id =  $row['id'];
    # e1 A- y% X9 k: c
  34.     }
    # r1 J8 _2 m0 e) u: P. @) Q
  35.    
    ( s, L# O) @0 t
  36.     if($id > 0)
    0 o$ Z# r6 O9 W7 O
  37.     {
    ( k- j5 Q# u  @/ @
  38.         --$id; ( W6 s- V" x( y8 M2 `: H
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 1 Y% U0 i& a- y2 s7 L
  40.     }
    3 c$ _+ I* j6 `- \  z2 |
  41.     # php的文件锁,释放锁
    ( c; b4 Q" K5 \
  42.     flock($fp, LOCK_UN);
    ( ~7 }* `& G) U3 M6 d5 [
  43.     fclose($fp);
    1 G0 r/ s; p+ @; j+ v5 S
  44. 8 S8 ^/ e5 ?7 H8 f% ?
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    / i  f: z8 C* _  u' u0 v
  46.     // while($row = mysqli_fetch_assoc($res))8 `$ A) c5 A! e% M
  47.     // {
    7 ^, u. ]) F' g) ]: u, D! q
  48.     //     $id = $row['id'];
    9 g6 Q8 G  q9 j+ Y
  49.     // }
    9 J% m3 V: _1 W8 G: n5 m
  50.     // echo $id;
复制代码

) z6 g7 w! i( I* z2 n) J
- ~6 w1 p0 o: [0 K6 ]$ d
抢券活动实例:
  1. public function envelopeSnatching(){7 `% Q( X8 i0 ?) [- @
  2.         $lingqu = $_POST['type'];
    $ Y! W8 }9 t" f, @5 c
  3.         $uid=session('u_id');//用户id
    ' w0 w  Y6 W6 c, B
  4.         if(!$uid){
    0 ?- X9 `$ D5 g1 I# C( U7 m
  5.             $data['msg']='您没登录,请先登录!';
    ! m3 ^: k( ]) ^- O! E3 }
  6.         }else if(date('Y-m-d') != '2017-12-12'){/ Q" I  T. R0 _2 Y9 W
  7.             $data['msg']='不在活动时间内!';# o' p0 b2 b$ s& ~
  8.         }else{
    2 q' d) c+ p; A0 [  m4 q. `& o' C
  9.             $hours=date('H');//当前小时数
    : C' p& w1 W: G& D4 j! Y2 k. |  S/ q
  10.             if($hours > '09' || $hours > '17'){
    4 \) Q4 U6 D, R3 E9 B. w

  11.   o- E) O, V2 M" s& X7 d2 S
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    7 J1 @* j& x! ~
  13.                     if($lingqu == 1){
    4 r. {# r0 ^: }3 t8 `
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过! d6 U7 d; N2 V$ u7 l! d
  15.                         if($hours > '09'){, L9 X! K' ^4 d& H& a" g6 ?, g
  16.                             $num=mt_rand(25,28);//优惠券金额$ o* c! Z/ G% \* L/ h" q
  17.                             $id=1;; O4 m# ]' ~1 o
  18.                         }
    - @: S6 ^) w4 ?1 f+ L
  19.                     }else if($lingqu == 2){0 t& U& S8 q0 o7 C* I+ S* {
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();8 N0 ?( i3 r# _
  21.                         if($hours > '17'){
    / O8 t* i; T2 ~" |5 F. i
  22.                             $num=mt_rand(50,55);//优惠券金额! P& N( A' t1 v) M
  23.                             $id=2;
    / ]; j; Q, k* m+ q2 d- S
  24.                         }
    , `# V1 R9 d2 i$ C8 z1 R5 W
  25.                     }4 c/ k$ ?8 m* j# a( j* i" V0 i8 g
  26.                     if(!$id){/ r4 i: a, e/ ^) c7 i8 z+ g0 Y
  27.                         $data['msg']='时间还没到,晚点再来吧。';3 B. {% `4 j( |( `
  28.                     }else{  S7 X: O4 M1 Q
  29.                         if($is_lingqu){
    & Z& u" H5 T/ z. A# y3 @3 B  M( J8 g
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';, v4 j% ^. `* _6 L1 I" d# [
  31.                         }else{
    # m* M- V# r( k* ^
  32.                             //锁表! D! n  b: ]# w4 s
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');- t& N" @- f" D5 E# w1 X* W
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    ' X/ s9 A- e; b3 Y; l( j
  35.                             if($active > 0){
    4 X& N4 T, e( T: u: h; _
  36.                                 //开启事务
    1 ~$ u# N9 g, N" s1 m
  37.                                 M()->execute('start transaction');. v  J8 W& a+ C* g$ _% N
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));4 V1 V( B8 P7 J3 N; h
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    6 u+ M1 u, k3 ^
  40.                                 $members_preferential    =    M('members_preferential');0 `0 ]5 u/ t' N: n4 K2 @" j7 b& K
  41.                                 //对应投资金额,  `6 |4 H/ j  g% X" ]1 o2 [
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    7 H, ]% i& C, t/ r  `
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');$ H/ k  L6 a; s  c: {3 P  N: s
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    6 `4 z* D2 Q" G3 K
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ! h* q6 l, `( V1 g
  46.                                 if($save && $add && $add2){" ~0 I" O$ C" F+ ]1 L& C% M
  47.                                     //事务提交
    ; Z- R) m! j& z. T# ?! P
  48.                                     M()->execute('commit');
    7 g# l2 c" a9 w
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    9 d/ {: T2 R& y* i) A  U( f( f$ Y
  50.                                 }else{
    # ~( Y/ H- |, R
  51.                                     //回滚9 d4 y7 E+ Q0 R1 r: X' f$ g
  52.                                     M()->execute('rollback');( l& O' L0 F7 x+ B
  53.                                     $data['msg']='未知错误!';! ~. P& j( N3 S4 U
  54.                                 }
    / s! R* T, n; P
  55.                             }else{
    2 o( J  \' D/ c, a( _4 X
  56.                                 $data['msg']='红包已领完,你来晚了!';
    6 [8 _4 j& x! k$ j
  57.                             }
    % y4 K+ `* _1 p, i' n
  58.                             M()->execute('UNLOCK TABLES');
    6 h. b0 B. a1 S3 ?$ y$ v4 M
  59.                         }
    + q7 s$ h! S0 i3 S, |5 J! l- [. Y
  60.                     }
    ' E. T8 T- l8 V! l( o/ g
  61.                 }else{5 W7 z* j) D7 @" {7 `% ]
  62.                     $data['msg']='非法操作!';
    $ C$ ?8 m# F6 T" i
  63.                 }
    : W8 M0 M& x/ e2 g* D: Q# ~" Z
  64.             }else{
    & ?& m$ z# X( L: w
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ( n3 G+ m: {+ v7 I$ p3 S. O) a" B
  66.             }
    3 V3 z# t- t7 j7 j' H" p% Q0 |
  67.         }
    ; `8 ~7 W/ ~' t3 Y8 d) g
  68.         exit(json_encode($data));
    ( Q. w: Y" c' t2 Z8 S" Q
  69.     }
复制代码

* k3 G+ H; p0 }
, z3 [* q- t/ `2 t/ j
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 18:10 , Processed in 0.061913 second(s), 20 queries .

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