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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8890|回复: 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://请求的脚本
复制代码
" w3 \% m; V% ~( Y5 l, C
Mysql中的锁语法:, D7 v5 F, p) ~2 k6 g, V; z
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】1 F, v9 C5 \& K/ P3 H- U6 W" J
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表: r' ^/ D0 ?; J+ b
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞+ }. r( [! n7 F* b
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :2 N/ }- p) h% x! z1 ]6 F8 ?
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
- k6 D1 R# W4 {8 J# z测试时,有个文件就行,叫什么名无所谓
总结:
' t4 N  R8 ?8 u9 r项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:3 J2 i8 p- y: l0 g, J7 q4 g
1. 高并发下单时,减库存量时要加锁8 R9 D/ Y! c/ k2 Q2 I* u6 p  d
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    6 o4 V5 ]* E# Z) U1 r
  2.     模拟秒杀活动-- 商品100件
    8 E# B# N5 ]; S
  3.     CREATE TABLE ta6 s9 |" z' O, @
  4.     (
    : e! s& t& M; p; Z4 C  s( _/ U& Q9 p
  5.         id int comment '模拟100件活动商品的数量'! W4 u, J  m$ X0 a8 M1 v, E
  6.     );
    / T/ k* ^! m( o# `# o
  7.     INSERT INTO ta VALUES(100);
    $ H1 h. b8 x( K% P8 t2 @, [
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    6 z9 Y/ A* |' X3 f
  9.      */
    8 X1 m+ U, W& q" o1 A# }4 t; @
  10.    
    0 u8 @# {4 P6 `1 a0 O6 Y
  11.     // 关闭错误报告" @* C/ r: X9 G$ p0 O  D0 L% I
  12.      error_reporting(0);
    , w: R" d1 ^0 l
  13. ! q& P% c4 h, A7 k" Z& d
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址$ X9 z* G3 X, g
  15.     $dbuser = 'root';            // mysql用户名9 u( C+ Y& ]+ z& g' s) N
  16.     $dbpass = 'root';          // mysql用户名密码
    : P! Y7 t5 C5 [6 }
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    * u9 J8 v- K3 I" }4 h: W. p: l- z
  18.     if(! $conn )
    : ?! m4 H" `- J, V/ S9 ?# j
  19.     {
    2 I  O$ d: \: K" k! v5 Z" T
  20.         die('连接失败: ' . mysqli_error($conn));
    , w3 U2 Z; U2 M: q( L2 Z0 k7 a6 M0 R
  21.     }
    * q1 f1 a1 u; G' P
  22.     // 设置编码,防止中文乱码* j6 p; A1 a) t
  23.     mysqli_query($conn , "set names utf8");
    2 a( @0 ]( \1 l* C8 v6 y# Q+ u+ i
  24.     mysqli_select_db( $conn, 'temp' );
    0 k  P, W. x, O9 O' a. |

  25. 4 W2 M* d* o8 G% ~1 t7 r+ z: P
  26.     # mysql 锁
    3 i) J! ]. ^/ e# S  O, n
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 # o$ n5 h& a" V+ T/ a$ E1 }3 b4 U2 }
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); & @6 @+ i3 o, d8 s
  29.     $id = mysqli_result($rs, 0, 0);
    . P' }9 C0 a* Y8 G% `) j; S6 p
  30.     if($id > 0)
    $ W- i( d% {  \- b- }+ |
  31.     {
    : y4 p. u: W1 t- H9 ~: @4 L
  32.         --$id;
    4 i4 u1 h- G8 s! M4 l. K
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 5 N# T5 v' k/ ~2 D1 z# Q8 I
  34.     }
    2 ]8 `$ z' o% x- G% U# t5 l

  35. % S6 a) W, w! P& X2 X
  36.     # mysql 解锁 ) R5 g# I3 n$ p; f% W
  37.     mysqli_query($conn , 'UNLOCK TABLES');% ~; i+ f' [- {0 S  I& b4 F
  38.     //查询解锁后的id值8 p4 S$ e, w' f6 b  Z
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    . @7 t" v7 P3 u! j
  40.     // while($row = mysqli_fetch_assoc($res))
    / b4 c' x) p+ L6 C' |
  41.     // {2 [) I0 N4 @8 N  m# ?
  42.     //     $id = $row['id'];% v$ Q& H7 e) s2 e* r/ {
  43.     // }
    0 z% d+ g3 U2 V- u) i- ?
  44.     // echo $id;
复制代码
) d5 x/ U1 m7 l: D/ M

% }3 ?( l4 b; z6 i+ ~5 |1 Z

9 U* J7 Z, K, O, P# L6 [: `
PHP文件锁示例:
  1. /*2 f. F8 S" N- \1 n
  2.     模拟秒杀活动-- 商品100件
    8 j. v7 d7 I, p; l' R0 W; G/ ~
  3.     CREATE TABLE ta1 R$ A( i! k6 q" z6 v
  4.     (5 t/ S# b, Q3 v) ~* c
  5.         id int comment '模拟100件活动商品的数量'" u: o" V1 e0 w' C: y( e- n6 \, [6 J
  6.     );
    ' k- O  U& B( u8 G3 _* L
  7.     INSERT INTO ta VALUES(100);* Y- ^* F8 j. O- G
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件0 [/ g( d. F" o
  9.      */ % _8 a, e8 c* ]7 r
  10.     4 s+ H' Q  `0 m$ ]: E
  11.     // 关闭错误报告2 B* J: O( K9 s8 L
  12.      error_reporting(0); 4 G% h. w+ R, B, G* Y
  13. + R9 m8 G4 U7 [! [
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    , d# t( a! _3 y, L0 }* A8 `  p$ `
  15.     $dbuser = 'root';            // mysql用户名5 I# j6 J  t& J$ L5 O. V6 |$ Q
  16.     $dbpass = 'root';          // mysql用户名密码  i% g% {3 ]5 H8 D
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    & j: q6 M0 @5 ?& P
  18.     if(! $conn )
    - O* e/ T$ I' _
  19.     {; _* m% T" ]# O4 v8 ^
  20.         die('连接失败: ' . mysqli_error($conn));. Z9 X/ O* o7 z6 v& q
  21.     }& `9 V4 C- D2 Z, i4 d* T9 F
  22.     // 设置编码,防止中文乱码
    + o; Q' h* {9 V8 ^5 m' v! Z7 E
  23.     mysqli_query($conn , "set names utf8");8 U# D: `8 ]& k1 P3 e
  24.     mysqli_select_db( $conn, 'temp' ); 4 B1 U  E! v9 H
  25. - d5 \5 q7 m3 F/ S
  26.     # php中的文件锁
    9 P2 J. \+ k8 M# u
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
      J6 q, {9 @' [( m1 a& w1 ^! f
  28.     flock($fp, LOCK_EX);// 排他锁 4 h5 z- B9 O' L, ^  }! U: _% n
  29.   A# ?6 g2 G5 p  E
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); , }6 Y5 p: A$ ~8 A# J& i
  31.     while($row = mysqli_fetch_assoc($retval))
    % m5 D8 c1 @+ b+ i
  32.     {6 L; C% ]$ W, u& a! B/ H
  33.         $id =  $row['id'];: _5 y0 t* u% P6 J7 a% w& W
  34.     }6 y8 Q4 O& L4 |/ A7 q2 ]8 X6 M
  35.    
    / j* x# [$ s* d; t$ Z, W( K
  36.     if($id > 0) 9 \3 N; r, E3 y$ w4 f! T" l" u
  37.     {
    0 @! ^- ^$ F* a6 v
  38.         --$id;
    ( B: L0 j/ M' T) p7 N
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); * F, T0 A; U4 ?- H
  40.     }
    % b) F4 K1 T. b, C4 x9 q
  41.     # php的文件锁,释放锁
    " F$ q  A: i9 k- H( g% }2 o1 `
  42.     flock($fp, LOCK_UN); / w3 y' @/ t- W  U/ c8 K7 `
  43.     fclose($fp);
    + B- L  |8 v& ]' G- ^4 y5 u* U

  44. 7 N& x' i! ~4 A4 d- E! K  c- y% A$ d
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');" r0 w" `: t/ X& x, j0 d2 t7 D; U8 h
  46.     // while($row = mysqli_fetch_assoc($res))
    ) W# x/ T1 w1 q9 y0 C. D
  47.     // {) [) v# U. \% `0 q$ G! w: ]
  48.     //     $id = $row['id'];
    $ {$ t4 f6 w3 q
  49.     // }" W7 `! W- I) P8 b2 j5 O
  50.     // echo $id;
复制代码

6 Z9 O) P$ m- G0 `4 B. @9 l4 A; p) l* D( U
抢券活动实例:
  1. public function envelopeSnatching(){
    " W5 C7 s1 ^. N& ]3 w2 s8 x$ c
  2.         $lingqu = $_POST['type'];
    8 L# h4 O( g! Z. c, F/ b
  3.         $uid=session('u_id');//用户id5 o# B$ f$ Q  {* O$ t
  4.         if(!$uid){6 M1 W, h! }8 V
  5.             $data['msg']='您没登录,请先登录!';
    2 Y3 E1 |0 h: _# O8 p9 N* E# y
  6.         }else if(date('Y-m-d') != '2017-12-12'){! t" _  R* E0 M! A
  7.             $data['msg']='不在活动时间内!';
    ' X5 a6 S. K4 M4 a+ {1 G& k
  8.         }else{
    ; y& T; {) E2 k+ r9 Q1 X
  9.             $hours=date('H');//当前小时数
    5 z  X; M: R# J2 k! L
  10.             if($hours > '09' || $hours > '17'){/ ~# p6 l4 ^& V5 O( t

  11. ; T2 {. G& _6 i0 `  ~9 X2 T; M- Z
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    ; |- i1 v  G  s
  13.                     if($lingqu == 1){
    5 X0 U8 u, W* B0 U  i
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    " c8 Z4 @* H: E7 @! s
  15.                         if($hours > '09'){' u* d4 q  d; z/ q! {
  16.                             $num=mt_rand(25,28);//优惠券金额. ^5 F) V! x8 S' ]4 o7 O
  17.                             $id=1;: c; S) B' @2 ]& U* O% t! E$ O
  18.                         }( Y# e; Y/ h) {4 B; J
  19.                     }else if($lingqu == 2){/ o1 j/ D% T( Y# L2 N9 U
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();2 _' f7 f8 N- n. f& E
  21.                         if($hours > '17'){
    0 R% A- ^9 _! j# e) M# K: w
  22.                             $num=mt_rand(50,55);//优惠券金额
    / \1 P5 L7 R# ^! S
  23.                             $id=2;
    ' ?9 m% \2 S* q4 u. n* u
  24.                         }
    3 a! G1 w2 ~+ g* T, |. b+ B2 E
  25.                     }4 `6 ~; o% s9 M# p( ]* z' J
  26.                     if(!$id){
    1 q( M) u0 j- r; G
  27.                         $data['msg']='时间还没到,晚点再来吧。';. p; F: }* Q: B
  28.                     }else{
    7 p5 j; K$ Y; E: _
  29.                         if($is_lingqu){3 n; l2 W+ w/ U' q2 E1 k
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    5 E0 d% M5 S2 F. a( K9 r3 g
  31.                         }else{
    0 a) a" I* L- ^1 l7 [- d6 k8 F  z2 B- \' Y
  32.                             //锁表
    ) ^( E$ u! E% ~) ~
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');, j/ B6 X! U% k* E$ L% t1 `
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();4 c8 k5 Z. f9 }+ t* m+ b% {: C* R
  35.                             if($active > 0){% x" Q& ~; d) t* l6 C
  36.                                 //开启事务
      j( e# Q* L  B6 ]# g3 Q
  37.                                 M()->execute('start transaction');6 K9 t5 _* O0 x7 U' }; H, E
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    + n: i# K1 N, b0 g
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
      ~1 o9 q) L( i" c
  40.                                 $members_preferential    =    M('members_preferential');
    5 U# Y3 R4 `- T8 W
  41.                                 //对应投资金额,
    , k! G; c- E9 T% m! T) T7 P- g. v- Y
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));* c- G2 e: ^# T5 G& A: L, `
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');6 g" o, c. g4 f. K' p' }
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
      m5 H" r9 |/ V, C6 W+ x! {" x9 G0 r
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券# |; d2 T  d  ]4 D
  46.                                 if($save && $add && $add2){
    ! `2 b$ }- N- C3 f$ ]% g
  47.                                     //事务提交1 q' C4 r4 Q% N. J
  48.                                     M()->execute('commit');! W# S/ G$ [  U% |
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';- R5 q/ ?- B2 D. U- @
  50.                                 }else{) m; i: ?6 ?! o. E: o2 P
  51.                                     //回滚
    " P& s: R2 L3 e! V, l
  52.                                     M()->execute('rollback');
    1 k1 p  L: H( }
  53.                                     $data['msg']='未知错误!';6 E, n0 z0 k. K! U/ F8 v
  54.                                 }
    ! N9 z& e( B, m4 N5 r# o, d/ y
  55.                             }else{
    7 ~8 d; J+ Z, ?" h) ?5 h2 h1 |' U
  56.                                 $data['msg']='红包已领完,你来晚了!';  G) w7 m' {7 l1 S
  57.                             }
      S0 \& s  h8 ~* }9 ?
  58.                             M()->execute('UNLOCK TABLES');& K( j1 j$ @. {$ {' \
  59.                         }8 x' m* i5 D4 P
  60.                     }  V0 k" I5 t2 f
  61.                 }else{  w( v( U4 Q3 |# Z  m
  62.                     $data['msg']='非法操作!';
    $ g" _/ |5 `4 N/ z: Z7 t
  63.                 }
    + v8 q2 C$ p$ G! l! k
  64.             }else{5 b; B. v# [  T, z8 M
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';- |: J. P  v( ^' w' D5 i! ~, |
  66.             }2 f$ Y: ~; a3 l" v3 a6 e
  67.         }
    3 B7 ~$ V! \$ G: T) c  Z8 a6 u
  68.         exit(json_encode($data));% D! X0 S% s* `$ P4 l2 a
  69.     }
复制代码

% Q1 V: j* k2 u4 q' [' P; h
1 y' Y8 r6 `5 m/ b8 }
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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