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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

  }* m# D! U+ P' T! K3 C+ R. ^- }/ [% R
Mysql中的锁语法:, Q) r  _; |+ w4 \! d6 \) C6 M& }
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】& X, t" }/ g$ Q, o: j# j* U
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
, Y' U* |6 d$ L& L- b+ J0 ?& iWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞# Z" J+ h) w! C; w0 T1 I
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
) I# d. i+ C6 E, U5 Q  Q文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。3 r, G6 M* U, p1 T) \
测试时,有个文件就行,叫什么名无所谓
总结:* V1 v: h0 Z6 Y; G3 K
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:3 T1 U7 X  K, q4 z# l. N
1. 高并发下单时,减库存量时要加锁7 n' R$ ~7 X" A5 `2 P+ z3 o6 ^6 Y
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /** I0 L# C+ `' h% k) u* N6 k* l! [
  2.     模拟秒杀活动-- 商品100件
    . w8 f  P$ P% a8 c' ?' |* D
  3.     CREATE TABLE ta. \1 b, C5 _/ A$ ?3 {$ V* ?
  4.     (/ `- c4 K8 J  x3 b
  5.         id int comment '模拟100件活动商品的数量'
    ; W5 g5 i; g0 I: ~* b+ b5 C. n
  6.     );
    ( l% M( q, a0 s3 Q9 q$ k
  7.     INSERT INTO ta VALUES(100);% n' G2 i2 u0 h
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    / _  c) y$ G) u$ L- }
  9.      */ # d: i* Z0 K0 D) n$ s
  10.    
    ; E. E8 J% |/ S) ^; ^! [
  11.     // 关闭错误报告
    - ~9 g- X1 I  H% \. P
  12.      error_reporting(0);
    ' [; z% L' [" l2 L# f
  13. # v% a# `- n/ B) }4 B6 Z1 ^
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址' W  u9 i' p5 k/ p* ]+ {
  15.     $dbuser = 'root';            // mysql用户名& k% ?6 h) t# V' r3 L5 ~8 _* C4 M
  16.     $dbpass = 'root';          // mysql用户名密码! a' L; H  U0 X; l
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    " Q* m) X8 z" R
  18.     if(! $conn ). |1 A; X' a" [
  19.     {! I3 c- s4 U# [: h* p
  20.         die('连接失败: ' . mysqli_error($conn));
    6 ?$ O, B) m& R" t0 R: A8 w
  21.     }' X! R" `, [% J; Y+ N/ }5 p3 O+ o
  22.     // 设置编码,防止中文乱码
    3 K+ [4 D$ o  E0 r0 J. Z2 ]! `" U
  23.     mysqli_query($conn , "set names utf8");
    6 ^  S# `5 r' L% q- ^
  24.     mysqli_select_db( $conn, 'temp' );
    " d* F  y7 F; X  \4 D& n- P
  25. $ E. _2 V7 b) P/ r8 m" A9 r
  26.     # mysql 锁 8 E0 l- a$ {0 D$ u5 T
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    4 ?2 Y0 T1 ]/ D. i7 L4 \$ _. J$ l
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    1 P) ~7 l& ^2 V& X7 }
  29.     $id = mysqli_result($rs, 0, 0);
    ! _' G. w* e, S- e
  30.     if($id > 0) 0 @; q9 J# H" e
  31.     { 3 l/ c) B! |$ V- i& N5 y
  32.         --$id;
    / N- J6 m2 A) v& G% @% Y+ _' T9 E: N
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    # R* E& C# @1 s& K7 O
  34.     }
    " }! H3 ^  i( t( N7 a7 M" k" c
  35. * I. g0 M! N3 |. a9 N9 ]: e
  36.     # mysql 解锁
    . q. f9 [* b" [+ `" F0 x+ L. [
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    . }' ?8 Y1 m. L5 E5 V
  38.     //查询解锁后的id值- J# y7 q- N& u
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');0 t, D2 {: L. n0 J
  40.     // while($row = mysqli_fetch_assoc($res))5 g7 {$ f/ A1 u0 `4 U
  41.     // {; E% P! K# |" k9 o
  42.     //     $id = $row['id'];3 R  q! ?1 b6 U' I1 L1 o
  43.     // }
    + [7 z3 J" i( A8 N8 S
  44.     // echo $id;
复制代码
% L7 O3 K8 \1 A* b; }! C+ C

5 [9 W' \  ^! g, E. b3 {
) ]. k1 q. [: ^5 t! |" S3 F# F+ o( \* N
PHP文件锁示例:
  1. /*
    2 C( g+ e7 [( B
  2.     模拟秒杀活动-- 商品100件
    $ [+ c) u- n' b# D! u
  3.     CREATE TABLE ta. `. n/ Z* q" a7 W
  4.     (
    , z  u# Q9 y5 t
  5.         id int comment '模拟100件活动商品的数量'& S" m3 R3 Z' Z5 {
  6.     );
    9 U/ d6 F; J% c- L7 G
  7.     INSERT INTO ta VALUES(100);
    - a7 p& ]' Q* o
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ' C4 A$ R% w$ ~4 F+ D
  9.      */ 8 T, c2 J: w( \+ y4 r" b
  10.     2 j& B' N+ @: G5 G2 Q  f
  11.     // 关闭错误报告. k5 _4 S# A6 `: S  s7 \* O
  12.      error_reporting(0); # c0 @6 I; D1 n- ?
  13. 0 h! x/ [% w0 Z5 K4 C  D
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( {0 R4 B& V5 F+ S% F+ O. M
  15.     $dbuser = 'root';            // mysql用户名
    % ]. t# m$ S- [' {# N
  16.     $dbpass = 'root';          // mysql用户名密码3 A/ h- B( T: b. E9 F
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);: r$ T7 ], N8 {- ?
  18.     if(! $conn )
    % w3 c% y! p7 N
  19.     {
    5 [! r% X" ]* Z* F) t
  20.         die('连接失败: ' . mysqli_error($conn));
    % o: }7 K( n) g3 W: a; v( o. S
  21.     }
    4 l+ e% M" D) i* w5 x) [- j/ R# z* b$ ?
  22.     // 设置编码,防止中文乱码
    7 }/ _; L% Y* z% Z' B$ o- \) P4 n
  23.     mysqli_query($conn , "set names utf8");9 v' T* Y7 \9 I
  24.     mysqli_select_db( $conn, 'temp' );
    ; m6 B) y5 c# d+ h+ E0 F7 B6 b/ Z
  25. , X  T/ {+ C' J# p% }/ [: R
  26.     # php中的文件锁
    ( N& L. ]8 C/ r; L% f6 z9 d
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    7 p* d# f+ y- r$ w6 ]
  28.     flock($fp, LOCK_EX);// 排他锁
      g  L  ^% e# @! c
  29. 4 f8 l* ^/ V& _' s. W0 N' j
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
      S8 i1 z& s  \. I
  31.     while($row = mysqli_fetch_assoc($retval))5 [( C7 V* f) m$ n( V1 h1 L3 ^
  32.     {
    $ d5 o% W9 R1 V$ U1 Z3 B
  33.         $id =  $row['id'];0 f# I! l! N. c& X# B% X) K: x
  34.     }4 [" Q, D1 S1 k, x4 J
  35.     * m7 F* ?8 k* f4 R* ?# p+ {
  36.     if($id > 0)
    6 ?( ]5 Z. ^- J- N7 P5 F* d
  37.     { & t: u5 o) ]% S, _* ^
  38.         --$id;
    - f" s8 _3 P6 A7 G- h/ n
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); + u! W. C0 K7 m$ J  _$ W6 d
  40.     } 6 p0 r! [1 o! S' Q9 D- m/ k0 ~" ~
  41.     # php的文件锁,释放锁 ' X5 l% P9 X# z3 u
  42.     flock($fp, LOCK_UN); , n9 _( X& J2 [2 D7 G
  43.     fclose($fp);
    " ]4 R% m: }: ?' L) w  G
  44. , B0 `2 S: f1 U. s3 |( E
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');/ P9 d! \& b8 `# Y' V* l
  46.     // while($row = mysqli_fetch_assoc($res))
    % i8 c0 f9 [0 B
  47.     // {
      y' ^# K, E* T/ s; [: A" G& V
  48.     //     $id = $row['id'];( `  j. Q$ y. p, z# I  z1 t; x7 c
  49.     // }( s0 |8 P8 S2 E% p' V6 D2 {9 v
  50.     // echo $id;
复制代码

; _( E3 K7 v9 {4 P# l4 A( ]5 u1 A
抢券活动实例:
  1. public function envelopeSnatching(){
    * F) Y) ?1 ^1 p9 H% Z0 k2 h
  2.         $lingqu = $_POST['type'];
    * R3 f. K; m( N+ \3 J+ `
  3.         $uid=session('u_id');//用户id) _/ p1 J) ^- p# G4 ?7 K1 g
  4.         if(!$uid){0 k3 T1 M6 Q' p7 p- a
  5.             $data['msg']='您没登录,请先登录!';6 f" P( ~$ K# g; K
  6.         }else if(date('Y-m-d') != '2017-12-12'){! N# x1 k2 Q6 i6 u/ ~
  7.             $data['msg']='不在活动时间内!';
    # T% I- Y2 {" |: n6 G+ M3 p
  8.         }else{
    ) }6 f! p( ?" l
  9.             $hours=date('H');//当前小时数
    / K* q4 a3 D1 w5 q, `$ f
  10.             if($hours > '09' || $hours > '17'){& S5 N7 _+ o4 n& v9 x) _7 V

  11. 2 T/ Z/ E1 }* n3 P" n
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    / [4 g7 f; F# }8 E. E
  13.                     if($lingqu == 1){7 |! ?& X  Q  ~& c# d" E( _6 C
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    , @+ r  D% w1 x2 t% X
  15.                         if($hours > '09'){7 ]$ ]( \8 }4 Z" {
  16.                             $num=mt_rand(25,28);//优惠券金额& L/ s4 b/ v- ]% u
  17.                             $id=1;2 a$ Y; b  d7 o5 n) B1 a
  18.                         }6 m+ o# N( m2 |& M# c
  19.                     }else if($lingqu == 2){
    6 \+ M* w0 i; h% J( E! D
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
      m  I) O5 I& g# m/ v
  21.                         if($hours > '17'){
    1 w. z- C, Y( O  N* A: `3 G
  22.                             $num=mt_rand(50,55);//优惠券金额
    / j+ c0 D7 L" A, y* d8 W
  23.                             $id=2;3 j4 x0 L# a7 }; C/ \! ]( \
  24.                         }
    8 s5 ^; h% ?8 B
  25.                     }8 ~& R3 U) ^9 C7 D$ \
  26.                     if(!$id){
    + g/ Q: e) V' m& ?. |9 w
  27.                         $data['msg']='时间还没到,晚点再来吧。';5 {+ b! _; C! ?+ z, ]3 y$ u
  28.                     }else{# R4 {* L9 _/ f9 }) U$ S1 |
  29.                         if($is_lingqu){2 a) t( N  `' }4 e
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    0 ]+ M9 U7 U+ G7 ^3 `+ ~
  31.                         }else{
    ; P- [+ Y7 S. e( u2 M5 X
  32.                             //锁表
    ! I" `2 D' Y+ `6 f
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');1 a& ]& V) m( X! R7 {) s$ u& W
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();: I% e. z+ g0 {* g! N3 ^3 T' Y
  35.                             if($active > 0){
    $ @# k0 N, L, x" j7 R' S
  36.                                 //开启事务
    1 J$ ~. F5 p$ C5 \" ?2 w9 X
  37.                                 M()->execute('start transaction');
    * f$ ?' j3 ^7 t
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    & w1 N$ E8 J7 C" B6 ]: N  }
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));( d; L0 x  {9 H7 l8 y
  40.                                 $members_preferential    =    M('members_preferential');
    9 k! `7 P, K9 D( H
  41.                                 //对应投资金额,
    " ~/ p& f; e- B, H! h! I+ P0 q) |
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ! g* U: }) H/ J8 L) O' _$ U$ ?
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    5 L; J1 P' \/ ^; ^
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间. A" V  g1 d9 Y% A' M0 d  _
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券" O* R+ N7 ^! A+ k% x, }1 V
  46.                                 if($save && $add && $add2){" m9 Z# ?8 r2 K' T9 F
  47.                                     //事务提交
    & B: ~4 K- g8 y
  48.                                     M()->execute('commit');
    - d# l) X- g9 A( M; D
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    - q; V" S: |' F  O9 h/ a
  50.                                 }else{0 U# C3 |* G9 Y" M6 ~
  51.                                     //回滚
    . [/ Q9 L6 d, c2 |- p2 I: J
  52.                                     M()->execute('rollback');3 p5 `+ F5 n  ~# F3 a  k
  53.                                     $data['msg']='未知错误!';
    , G3 Y% t% V( N$ c( q
  54.                                 }
    * b+ Q% J! o: U1 c8 o. e7 d- U  @
  55.                             }else{& i0 f1 Z2 q3 ^4 j& x% Q
  56.                                 $data['msg']='红包已领完,你来晚了!';
    % ]8 v% f: ^- E+ f3 \) Z( E
  57.                             }6 o- ^2 m( S( s# V
  58.                             M()->execute('UNLOCK TABLES');
    + G  D% P( k: [/ X
  59.                         }' E  [' n  b( b8 J1 n7 {
  60.                     }' Q* F# `! X7 j2 y% l
  61.                 }else{
    & g, O5 A9 d; N9 z
  62.                     $data['msg']='非法操作!';
    0 d6 l; d! \) o/ k( R6 I
  63.                 }
    ' p/ s8 G% W/ H6 ~4 |8 J* _! b: v  F
  64.             }else{# j8 f0 ?& T; ]2 G' t3 Y; c9 S8 v
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';) E( w  g6 W& i0 k$ P# W6 R0 U
  66.             }$ Y* c* e, b. m2 U4 \1 L- W
  67.         }
    % y; e& E& n" A9 A
  68.         exit(json_encode($data));
    # F0 Y& s3 W1 C0 {4 V( J* `1 H
  69.     }
复制代码

3 A1 i) \5 Q/ A2 j
4 q  m' L& {" E, K) }4 y( A  z+ d
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 15:52 , Processed in 0.053792 second(s), 21 queries .

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