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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9332|回复: 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://请求的脚本
复制代码
1 D( o( v* x" J! [, ?4 T
Mysql中的锁语法:9 W$ j' S# J: j! ?* c
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】9 n, ~9 `6 Y, P) P# C
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
  d! F' g7 f8 ~" DWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞! Q6 \" `, G/ A
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
/ Q% a  k8 D% R0 Z% u文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。, o6 _1 z  L  V+ [7 Z" x: y
测试时,有个文件就行,叫什么名无所谓
总结:
* j: f8 J3 X6 ?; p2 a/ R项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
  ?& ~: E5 Z* u, @) K7 g1. 高并发下单时,减库存量时要加锁- G. A! C- u/ X1 G! V
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*/ z, K! q  L0 G9 ~
  2.     模拟秒杀活动-- 商品100件
    8 B2 e; L" C' H+ W- a- V% {7 v" Y
  3.     CREATE TABLE ta
    + ]7 O5 F. @% T- N, C( f
  4.     (0 e% P: s/ J5 M+ F0 y; V
  5.         id int comment '模拟100件活动商品的数量'
    4 h2 v6 p3 N9 H
  6.     );
    ' a/ V% \+ W5 U' _/ `
  7.     INSERT INTO ta VALUES(100);
    / T. w2 Q" N) j# ?5 O1 ]& Z
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件) R0 a4 {  H: N1 A# A. d
  9.      */
    3 ~" A3 P) b* b2 g+ f" F
  10.    
    * M) Z0 A. d' ]
  11.     // 关闭错误报告5 N/ I7 t2 @. |5 s. S- n1 p  K
  12.      error_reporting(0);
    ' y* ~; X8 R% S+ ~- }

  13.   G9 a& T, K! R0 q! P
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址" ~! d# @- T. f# [' K7 |  j( w
  15.     $dbuser = 'root';            // mysql用户名$ U& K. C/ B( ?7 _
  16.     $dbpass = 'root';          // mysql用户名密码5 H1 n  W: I2 G- {
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);8 v( T% |$ K* |, j
  18.     if(! $conn )( K& i; `5 a% q: n9 ?
  19.     {
    0 }  W7 g' m& ?# i5 j1 p9 R
  20.         die('连接失败: ' . mysqli_error($conn));
    $ T' Y. n: U' K
  21.     }
      _8 a8 ]. X" \, T7 [
  22.     // 设置编码,防止中文乱码
    9 v3 C4 E; l1 t- h3 Z
  23.     mysqli_query($conn , "set names utf8");
    : N- v( [: S7 I
  24.     mysqli_select_db( $conn, 'temp' );
    ; N) E4 G% I3 F
  25. / T& b1 O" f+ @6 l& Y
  26.     # mysql 锁
    ; A% d& I# l8 ?" P3 G
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 5 T4 i1 z, b, I! c$ T( ^) [
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 6 n1 u/ y9 t  R$ w7 \) a" r# y3 M4 N
  29.     $id = mysqli_result($rs, 0, 0);   m8 g+ q* i- G! ?
  30.     if($id > 0)
    ' G6 G( K0 F# r% C0 W
  31.     { * }/ r1 g- l( g4 d& I
  32.         --$id;
    8 H# V; v" \" P( r9 g- |" {& Z
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    . L/ t2 O5 d' `3 G5 F' C
  34.     } 7 {4 S+ m- V# s4 @
  35. 0 s8 w& C. |4 I, i
  36.     # mysql 解锁
    , Z# |  `. N/ i+ z& ~1 p( A
  37.     mysqli_query($conn , 'UNLOCK TABLES');* L& o5 ~8 v6 F; |$ L
  38.     //查询解锁后的id值, t$ y' ~7 F, X/ G7 D3 \' `
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ! N$ o$ j2 h1 d. Q1 p
  40.     // while($row = mysqli_fetch_assoc($res))
    ; m4 R% D  K7 T5 V4 o* \
  41.     // {9 E. B  }  N+ U3 n7 ?5 [
  42.     //     $id = $row['id'];
    7 ?! J6 U1 |- R; \" p
  43.     // }. m+ n# F% `% V- X' f
  44.     // echo $id;
复制代码
' _  r3 k2 J6 W& q+ C3 G8 _

3 p0 u: C( H, n  |
) J/ N1 u; ~: W! j
PHP文件锁示例:
  1. /*
    " a* S* ?7 B# G; ?; {; r
  2.     模拟秒杀活动-- 商品100件. n0 k3 f: e2 L& V( U) m+ Q5 T
  3.     CREATE TABLE ta
    : S+ b# f/ o+ q5 v$ M2 P! ]' C
  4.     (
    : C- R1 p) f4 a3 w
  5.         id int comment '模拟100件活动商品的数量'9 [8 F, ~6 w( H
  6.     );3 H' f$ q' d6 A0 P4 E* Z
  7.     INSERT INTO ta VALUES(100);& \( ^5 j5 J+ n$ `
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    9 J7 P9 I# t# o4 E9 Q0 ]1 R( i3 h7 ?
  9.      */ ! H' x  @1 E7 m  N
  10.     ' B2 N! _: @2 O0 q: w9 S8 f5 H: h
  11.     // 关闭错误报告! h2 c) y8 l$ ]
  12.      error_reporting(0); ; r7 }4 h5 C9 J$ `! I* [

  13. ( H' U$ d; b/ h# Z$ W
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址7 }% X; u* v8 ~- d7 c. G; z# N2 W
  15.     $dbuser = 'root';            // mysql用户名
    , H  B" w2 {) f/ p3 n2 V9 z
  16.     $dbpass = 'root';          // mysql用户名密码8 k) V5 M: p( ^$ x* n
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);0 Q8 V$ T# y5 E6 @" ]
  18.     if(! $conn )
    $ K! K& h4 K, A) N0 ^) y, I  @: E
  19.     {5 }; u4 L) u/ Y9 y
  20.         die('连接失败: ' . mysqli_error($conn));
    / F, j+ g' C1 i( j) b
  21.     }2 M6 z6 Z3 Y; f+ }* E2 E% L9 f+ ]- N
  22.     // 设置编码,防止中文乱码
    2 T( c5 I% X$ M. h, \
  23.     mysqli_query($conn , "set names utf8");2 `. C6 Q; w, m% _: G8 X
  24.     mysqli_select_db( $conn, 'temp' ); % E# t# p$ }6 T, p8 I- R

  25. * ]* w+ t' q1 b/ U
  26.     # php中的文件锁 1 r, ~4 l: ^" U/ \* R% P. l
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 & p; k, D4 d, R6 h) C5 ]0 D
  28.     flock($fp, LOCK_EX);// 排他锁 * X; |0 g, B1 I. i& r. T$ |
  29. & }: V3 x: y9 Q2 y! v/ _2 O
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    3 \0 N) [1 |# v  [' |* J6 ^
  31.     while($row = mysqli_fetch_assoc($retval))
    * D. Q$ T& _: m
  32.     {
    4 j* `9 J, y. C
  33.         $id =  $row['id'];& A( v7 R/ U- w  j. e1 _
  34.     }
    ) I7 ^2 T5 o2 `- E
  35.    
    8 ^; k% x* r2 e9 \8 S- \2 I+ g8 y
  36.     if($id > 0) * X, K6 S9 S$ O  T: x: \
  37.     {
    3 y& ?1 U) ?* T  G: v
  38.         --$id; ' m/ y  _, C& s6 ^' X. ?- W
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    * d7 v- B: X) M7 k; ^8 s# T
  40.     } 9 [8 s5 g4 H3 i( Z2 Y
  41.     # php的文件锁,释放锁
    , ~/ E; g! y6 s( W+ w- b
  42.     flock($fp, LOCK_UN); ( I4 g7 o% ^+ j* C9 A1 K+ o$ k
  43.     fclose($fp);* Z' F$ |* Y5 C# K4 k  G& x0 s

  44. ' V: d$ X) g8 ?2 ?, w! H% q
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');5 F4 B( I  u/ Y9 C& ?% }8 u
  46.     // while($row = mysqli_fetch_assoc($res))4 f! ^7 \$ x& s$ s1 [3 u. l
  47.     // {' g& f) Z/ F2 `; @1 J% U) D( S" p
  48.     //     $id = $row['id'];# {/ \) F, |) o8 B; ~
  49.     // }3 {0 m9 G0 S- C$ w. I* P0 l
  50.     // echo $id;
复制代码

4 F* p. F' X+ Z9 I( O, i0 D5 c! A# f. I, e
抢券活动实例:
  1. public function envelopeSnatching(){
    0 D8 X9 Q8 f$ i4 h0 i  v
  2.         $lingqu = $_POST['type'];
    ! Y, u8 w5 ~! n0 r/ z
  3.         $uid=session('u_id');//用户id
    4 W4 Z* A2 p+ F" T
  4.         if(!$uid){# x, T8 ~$ w; l' }/ I6 E1 n1 @/ b+ m& R
  5.             $data['msg']='您没登录,请先登录!';
    8 q9 `% x7 S) j( Q2 B8 N9 ^4 k
  6.         }else if(date('Y-m-d') != '2017-12-12'){  d" c: L! q' r. x
  7.             $data['msg']='不在活动时间内!';
    # p& n* `0 [! z1 F1 W- [
  8.         }else{* h; I( K& L- B9 D, W) B: d' T
  9.             $hours=date('H');//当前小时数5 l& ]& K. k% H5 s/ S0 [: {/ w
  10.             if($hours > '09' || $hours > '17'){7 Z+ y; b7 ?5 P& Z+ c  A
  11. 0 W+ r9 g4 \: {) A6 G1 k
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    7 W/ z- A' n8 M7 @$ Y- d# @0 U
  13.                     if($lingqu == 1){
    0 }- Z/ {* T1 L
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    1 z& |% B7 ~( k
  15.                         if($hours > '09'){
    ( T1 x+ x, M2 Y0 H* p$ G" [2 H
  16.                             $num=mt_rand(25,28);//优惠券金额
    5 ]" x/ _3 X0 P
  17.                             $id=1;
    % g3 ?3 ?7 c8 X$ }" A; z8 ]3 q  e8 s
  18.                         }
    : f8 E1 ]# P6 @( z
  19.                     }else if($lingqu == 2){( l/ {* e4 {$ C* E3 D% O' {
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    7 L0 b" H: V* a/ a7 j( q; x& S# Z: ~
  21.                         if($hours > '17'){  J, }! h$ G" U+ D
  22.                             $num=mt_rand(50,55);//优惠券金额
    - D. ~( R. L, P! M! e0 d1 q
  23.                             $id=2;' ^) z* i; i7 O( Y; z
  24.                         }
    , Z: B, V4 F: ^3 h/ L  v5 w0 `1 f
  25.                     }0 ?% I6 x5 Q9 [- E9 r1 H5 u
  26.                     if(!$id){
    - w5 k! j% A3 d
  27.                         $data['msg']='时间还没到,晚点再来吧。';6 {- k$ V) l0 q
  28.                     }else{
    7 k' b  n( q+ K% X  m
  29.                         if($is_lingqu){2 b- U  c5 Y5 x% w& t" b$ }
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';0 `, G# ~. P9 i: G$ z, P
  31.                         }else{
    3 [3 F+ i0 V4 b: n3 g% f
  32.                             //锁表- Y, B/ N7 H% o& Y
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');) A! }5 y& E, H+ r# ~% G3 C
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    . l3 v0 |6 ]' j* _8 x0 c2 {  I
  35.                             if($active > 0){
    ( u+ C. \( @# W/ e# J. X
  36.                                 //开启事务
    * t0 l5 b1 M3 o& D7 h
  37.                                 M()->execute('start transaction');% I% s. q# J6 N$ }" h
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));- I: w7 w4 q) L) f' D3 [' p5 \
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));4 ^* X( W3 E4 r' n
  40.                                 $members_preferential    =    M('members_preferential');) P7 e2 e- W3 {+ p# D& J
  41.                                 //对应投资金额,
    0 X4 C. i$ j- |2 b8 J6 Q
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    * U+ N  D$ l! p% h- G# |* W
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');! M9 \" m2 H4 M: H4 B- c
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间5 R0 K" I0 q7 t! ~- B! l* J
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券9 ]1 h$ I' c* h! y& B  f
  46.                                 if($save && $add && $add2){
    2 O* k- Q7 O2 G1 Z1 C+ v) v; z0 X
  47.                                     //事务提交% o( l; h! m9 U8 }
  48.                                     M()->execute('commit');
    ! K/ W8 V$ y: o$ d# f6 j
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    & R1 Q8 L1 A# n3 g
  50.                                 }else{0 C  C* `6 e: E
  51.                                     //回滚0 S8 b, H7 J8 N' |* T6 h
  52.                                     M()->execute('rollback');1 I5 }+ G+ h5 ^/ P3 j) N# W) v
  53.                                     $data['msg']='未知错误!';
    ) X8 c; @" ^5 P7 w) @
  54.                                 }0 k* F% r% e+ P; @" B) o- q9 ^! O
  55.                             }else{
    7 R; A& }$ t" h- m
  56.                                 $data['msg']='红包已领完,你来晚了!';
    1 s, L( ~2 [. _4 t# V5 d9 r
  57.                             }
    : \- K8 ~1 T8 l, D9 c5 p3 X( s  [
  58.                             M()->execute('UNLOCK TABLES');7 I+ y6 c% a( u9 m4 ^6 R
  59.                         }2 ~" Y! D4 Y( j& E
  60.                     }  s0 u& ~: ?' w2 W/ E
  61.                 }else{# f/ ?4 [7 g  e; g& |  ~9 n: [
  62.                     $data['msg']='非法操作!';
    ! x3 E0 f% \7 b4 z3 }; f) i% r' D
  63.                 }$ J. l- b0 ^$ D5 I. B
  64.             }else{) m+ ^( E% L. F5 ~' D! Z2 y
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';- [* |9 l2 h+ m( k2 r% V
  66.             }
    $ o4 i# ]. |6 U8 `
  67.         }4 {7 M) W& G& s$ p
  68.         exit(json_encode($data));7 k# `2 I$ Q. x/ B
  69.     }
复制代码

. C% K$ G% Q9 m/ a; A. A& b- Y& T& M
# L2 Y1 u' _  c2 p% C$ e9 j
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:47 , Processed in 0.076922 second(s), 20 queries .

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