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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8895|回复: 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://请求的脚本
复制代码
/ U2 j# D  {) k: g) @3 `% t5 J
Mysql中的锁语法:
8 }! x0 e# n& W+ o& VLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】9 ]* J/ [1 t% r% z. m: I9 ~- K. C  R8 U
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表1 [* g4 R9 k. v  f! W5 u
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞4 n) y1 w, L- V0 c% e( g
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
- ]5 \3 t" E/ M, q) j" q文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。$ o, }8 Q9 V' }, {8 Q
测试时,有个文件就行,叫什么名无所谓
总结:
8 E0 C' H6 g6 ?, P4 n) {' Y1 Z项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
+ W% u+ [( G  r+ G- S1 }- T1. 高并发下单时,减库存量时要加锁
' y* ]$ C0 y9 k2 R1 _2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*/ @( X4 _# A4 @' H
  2.     模拟秒杀活动-- 商品100件4 V/ x6 a- B! m, K7 [
  3.     CREATE TABLE ta
    - R8 ^$ Q$ a, g4 l7 ?( }1 b
  4.     (
      a3 C  M0 F2 H9 J: E8 y& x
  5.         id int comment '模拟100件活动商品的数量'0 p) Q( ^# E/ \1 ~5 u+ K3 b- s0 U
  6.     );% ^% [; N4 j& h( w' ]
  7.     INSERT INTO ta VALUES(100);) c* i6 ]0 i4 Q9 T
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件2 Y  H" O7 C6 S. k, t
  9.      */
    4 P3 s( `9 s: I! x
  10.    
    4 _2 `5 w' y2 c: o+ y
  11.     // 关闭错误报告
    . [; c+ w) C# v0 ?3 I
  12.      error_reporting(0);
    / u: o: n6 t! B

  13. + I& T9 Q3 N' p4 `
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址# p; x. o; Z3 I
  15.     $dbuser = 'root';            // mysql用户名
    - k/ P; W' Y$ h  P+ X/ z/ N% T
  16.     $dbpass = 'root';          // mysql用户名密码
    : Z8 @7 ^4 D9 E
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    / ?1 ]7 E- U3 e# U
  18.     if(! $conn )
    $ {. k' |( L. D- B0 y
  19.     {3 v+ [& P  q. o7 L
  20.         die('连接失败: ' . mysqli_error($conn));4 B5 d# I2 ?6 t& I/ v: g6 @3 t
  21.     }. a; S! ^" w3 C( e7 ~
  22.     // 设置编码,防止中文乱码
    1 M* h2 g- m9 I. p1 `5 ~1 m
  23.     mysqli_query($conn , "set names utf8");
    , |$ p  e7 G4 C, [  S
  24.     mysqli_select_db( $conn, 'temp' );
      \6 G( r6 f( g( y
  25. 5 F$ E7 S! y. ^1 y6 [
  26.     # mysql 锁
    8 g; S  Z  ^, f+ s0 _
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    ( i* ]' K8 f6 U1 ^
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); / m6 e! T9 K+ K* A
  29.     $id = mysqli_result($rs, 0, 0); , r' g" K8 u: C! D3 Y
  30.     if($id > 0) 9 `9 K3 A- E  p$ s. `: d# Z* a
  31.     { 4 T7 D+ K) k. V% d+ J$ ?
  32.         --$id;
    7 d( K- T) }" c
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
      g; N+ Q( _1 g
  34.     }
    ' C% j( ^0 H) _% t
  35. ) h) j4 \% @% q2 a- y& k# t7 G1 r
  36.     # mysql 解锁 , C& |7 K' f% S" g
  37.     mysqli_query($conn , 'UNLOCK TABLES');6 S3 C. W% B# [# E* K! P0 Y
  38.     //查询解锁后的id值
      ]5 m  d8 A4 B1 v% S
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');* k: ~: C6 I7 q. E  \& ]6 Z
  40.     // while($row = mysqli_fetch_assoc($res))7 [* k1 L$ j0 \; {
  41.     // {
    ! U  i4 g0 X4 [6 `+ m+ M+ d5 C  w/ t
  42.     //     $id = $row['id'];# A5 O! Z& D1 G" o/ F
  43.     // }
    * c" J9 }. d0 M2 h" v* n
  44.     // echo $id;
复制代码
+ F. O: U6 Q4 T, i. k

- Y3 l' U9 c! p! b/ c! a

8 ?( r2 |5 P6 f5 _& {
PHP文件锁示例:
  1. /*4 S% d0 X% r! F
  2.     模拟秒杀活动-- 商品100件
    + V; X! F$ x- E$ Z9 S
  3.     CREATE TABLE ta
    ! O( I+ j. z0 k( @
  4.     (
    " `6 y) a" i: p3 |7 X  y2 i
  5.         id int comment '模拟100件活动商品的数量'/ v" d, {4 Z* E9 _% x
  6.     );
    1 U7 E1 g  U! g! D
  7.     INSERT INTO ta VALUES(100);# ?! b( n9 Y8 j5 ^" Q" }* E
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件! k) S( ^* L+ }( c
  9.      */ ) D% O9 F8 B0 T2 X  W
  10.    
    3 H' V8 o; o4 E% ^1 S
  11.     // 关闭错误报告' ~* t; x  c2 `. E9 Q9 _
  12.      error_reporting(0); , @0 w6 P; D/ h

  13. + D- i" Z% D+ S8 c/ J0 y( v
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址8 d( g1 C8 j; `6 ]( R
  15.     $dbuser = 'root';            // mysql用户名% H/ B' l6 L+ K# q! Q, P
  16.     $dbpass = 'root';          // mysql用户名密码6 D  Z- v  }7 I% l  H
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    # i, ]" y+ ]4 K
  18.     if(! $conn )
    ! o3 h7 F: C" E5 j7 C
  19.     {+ O9 J2 t) O( d! a$ e
  20.         die('连接失败: ' . mysqli_error($conn));
    + k: M- M# @( u: w- }) h
  21.     }9 M. Q- D% {6 T5 O+ A) A( r  h
  22.     // 设置编码,防止中文乱码
    # r8 j  h* h& }/ b; d3 i$ A
  23.     mysqli_query($conn , "set names utf8");6 z* l6 K0 M/ N1 k0 I5 ~9 S
  24.     mysqli_select_db( $conn, 'temp' ); / U3 c0 a, q( ^: }
  25. 2 ^0 [+ A$ B( }' n
  26.     # php中的文件锁
    + j5 [& ~/ \. O/ w
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    1 f% ]6 k  G1 o
  28.     flock($fp, LOCK_EX);// 排他锁 ! u  B! @* x# j4 _

  29. / Y8 e1 Y/ d. I7 |9 U$ X7 [
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 0 x$ a- J0 [( m& h1 n6 _; [: a& u
  31.     while($row = mysqli_fetch_assoc($retval))
    6 s: t2 }) Y, l4 J: }% Y9 ?7 q6 \2 P  k
  32.     {8 F% x: S1 s6 e* O7 A0 F7 _" ~  x' ?
  33.         $id =  $row['id'];
    - v+ D; r4 h5 q3 X1 T9 g
  34.     }7 [4 U2 n8 }) H, _+ k- I
  35.    
    9 Q% l: ~* ^1 g% v/ i
  36.     if($id > 0) # e; T  T4 @3 T6 C6 e! M! c8 h
  37.     {
    3 |3 Q8 l8 ]( B' I
  38.         --$id; * Q$ B3 Q2 |1 T
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 7 L# b% G2 b' V1 f, k# Q, o) ^3 l
  40.     } * a9 ?1 ?# W. Y4 A
  41.     # php的文件锁,释放锁 2 m+ a( I8 X8 X% h6 ?0 @8 Q; o1 ]" C5 w
  42.     flock($fp, LOCK_UN);
    % T3 {8 M  X7 G! L0 p* _4 c3 t* h% f
  43.     fclose($fp);) F; u: |  Z8 N$ M# d( t

  44. 3 e% ^" s* y1 s. j# w
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');" w4 \0 R& y4 r# w) U' }: X
  46.     // while($row = mysqli_fetch_assoc($res))' I: l1 A2 r) `4 F! Z; w  I
  47.     // {
    6 _% D* C* g" s; G0 }" R
  48.     //     $id = $row['id'];( U& p4 m7 A7 ~! j/ n) f, i
  49.     // }  L2 K- A( {2 }
  50.     // echo $id;
复制代码

8 U1 H, H& [; P
! t- @8 Y6 r3 y5 y- l
抢券活动实例:
  1. public function envelopeSnatching(){
    ! G% k; _% ^0 M
  2.         $lingqu = $_POST['type'];6 z6 f2 k) }7 t; g( n) ^- L2 ~- k
  3.         $uid=session('u_id');//用户id
    3 t- ?" Q4 }  W3 M, G
  4.         if(!$uid){- M$ S% \" g* ~% k9 o
  5.             $data['msg']='您没登录,请先登录!';* ~, M9 O% B: y% @6 x+ t- @6 X
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    ) X+ O$ m' d1 C8 ]- d
  7.             $data['msg']='不在活动时间内!';7 U( N' ~' z0 W3 k( L1 t( @
  8.         }else{- I+ I* U7 K0 D& D9 A9 T' T" f
  9.             $hours=date('H');//当前小时数, C( S8 Z6 W  F/ v1 R0 `1 w
  10.             if($hours > '09' || $hours > '17'){+ L$ n: K& |! {4 c( o  ]
  11.   [7 p% I. b6 G7 c. w4 b. x
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的- a2 _+ O: s, u% b  W6 ^
  13.                     if($lingqu == 1){- Q3 K8 r* y5 `( E4 U6 {
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    5 ^0 ~% }5 ~4 z3 U* L+ n& q8 D7 e
  15.                         if($hours > '09'){
    $ l; a1 j( n( l5 v" J: Q( D$ p4 ]
  16.                             $num=mt_rand(25,28);//优惠券金额
    2 C7 w9 @) o, n. ]
  17.                             $id=1;* m% x& Y8 o- u" ?! `" Y0 Q0 O
  18.                         }- U8 c, k% @- S' I% H
  19.                     }else if($lingqu == 2){
    : g( j/ o9 K, o# t+ q# o
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();, ~* z! s) c& L& F3 C
  21.                         if($hours > '17'){; G4 {9 n3 i, m1 \; t/ c6 w
  22.                             $num=mt_rand(50,55);//优惠券金额
    : B" N. q# \5 `5 U  l1 l
  23.                             $id=2;
    ! P3 j9 V; u  Q' Y* k3 X& p+ N
  24.                         }
    8 P& n+ O2 d2 o
  25.                     }( |2 O  E; |0 k1 i. X7 o" _  t' r
  26.                     if(!$id){0 P2 q( J2 H. ~! A: _
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    ' Y$ i1 U/ l. p
  28.                     }else{1 t, d0 d& N2 D
  29.                         if($is_lingqu){* G! o" i1 t& ]/ {7 E' z
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';, o4 ^" K6 o( J# y9 c1 Z
  31.                         }else{
      T( O3 d$ P; u! q9 E/ e$ K6 Q5 D+ L
  32.                             //锁表; v( y1 M1 E, Y6 h# O
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    0 l4 D4 _2 E9 Z  ~
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    5 Q, [: ?- ]  Z0 ~9 ~% \5 ^
  35.                             if($active > 0){% F. Z) X+ D9 n* j$ F' M: }( i
  36.                                 //开启事务
    5 ^$ V2 r1 r/ Y9 r0 V2 ^. h
  37.                                 M()->execute('start transaction');
    ! B7 V, J0 I6 y. H5 O* d
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));1 Y( k, {7 V- A1 `( N6 r" v
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    & V9 E; f. R# ?, n5 H9 x, p* y
  40.                                 $members_preferential    =    M('members_preferential');, K4 O( m1 Z9 p- o9 U4 L
  41.                                 //对应投资金额,
    5 {. `, D! y) `) Z
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));) ?* i+ ~1 B; I; j: o
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    6 J' s. T3 l/ J
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    , B% K$ h  n8 M  F; a
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券7 g2 q: e' A# u. C- X4 [" H
  46.                                 if($save && $add && $add2){
    : t* M1 O4 ], T
  47.                                     //事务提交0 N- N8 j9 A8 Z% A$ u& A/ W
  48.                                     M()->execute('commit');
    2 a2 N. b* S6 a1 q/ B6 s( M
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    4 q3 \1 W- \/ S+ o, r
  50.                                 }else{
    & _4 {4 V3 r2 g" ~. B
  51.                                     //回滚  ^# {* `# a; ^+ M- r. z4 ^
  52.                                     M()->execute('rollback');
    3 G3 M# z1 @9 Y
  53.                                     $data['msg']='未知错误!';
    5 i3 @/ K1 S# _1 }( p6 Z
  54.                                 }  h8 B* @- F) ]) e0 h9 o# d- K
  55.                             }else{, d4 q( G: r+ u  H. _4 \0 |
  56.                                 $data['msg']='红包已领完,你来晚了!';9 B, B4 y: w, D1 F3 u, W2 U8 T
  57.                             }
    . p5 v6 S1 R" W4 B! _
  58.                             M()->execute('UNLOCK TABLES');) y9 K( h/ E# C. O7 r
  59.                         }
    0 B# }7 \3 ^: z% P! o8 c# h
  60.                     }
    5 M2 n. n2 l+ ^& i1 r/ q' O
  61.                 }else{
    , F1 n. m! f6 _
  62.                     $data['msg']='非法操作!';0 ]! h% H% E4 M+ V$ _% |6 t* `
  63.                 }; T) m4 N  L0 {/ `4 [, x1 u
  64.             }else{
    # r& j9 T7 r) k/ }# H  q
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';1 w( d) r/ K- e+ p# L! I1 @
  66.             }. l2 {6 Z% Q5 ~4 G( [
  67.         }
    6 ?1 ]2 R1 d& T6 D3 I9 ~, O
  68.         exit(json_encode($data));
    6 c, H( M; K( {9 ?3 r+ C
  69.     }
复制代码

# O, ?% w' S- _. E+ P0 m
7 V: J" T8 X; G" Y. L" ~
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 00:01 , Processed in 0.052822 second(s), 19 queries .

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