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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

; z: {3 G8 f* _/ F. b; F( a) k' d
Mysql中的锁语法:2 h; m$ Y" U: C1 p  B1 N) K
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
% v3 \. ^( A0 m8 }5 b) tUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
5 y+ Z3 b% h; Z# J2 n1 SWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
; O. ]/ p! {5 o- T8 z$ H. a9 C1 S2 R注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
) _% m8 j1 H; J) F. g- U7 H* _文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
% e# O! G7 o% Q, a( n测试时,有个文件就行,叫什么名无所谓
总结:; P+ ~1 y; F& x) i) p6 O. ^
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:5 y+ ~* ~$ `& }2 i- T1 }4 J
1. 高并发下单时,减库存量时要加锁
! B  S4 w% r. X. j/ k; U2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    . r$ J+ x( [+ |- c3 J
  2.     模拟秒杀活动-- 商品100件
    0 p; l' H: S6 A5 a7 s
  3.     CREATE TABLE ta
    & k* n7 L* o: A
  4.     (
    ' ~7 K+ g* C4 E4 Z
  5.         id int comment '模拟100件活动商品的数量'* [4 K( `& v7 m. t7 K9 q5 C, Y% p6 k  N
  6.     );
    - x( V- t: O. ^) `. D. y
  7.     INSERT INTO ta VALUES(100);; w# N8 t' R% C
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    7 k) G3 i+ s2 `. v' m4 N. g+ h1 y
  9.      */
    4 ~2 ]7 T8 I4 H$ |! h. w/ d
  10.    
    ; k4 ?( j& ^+ P. J' T- o  m
  11.     // 关闭错误报告# i7 l! [9 L2 t9 M' t2 V( I
  12.      error_reporting(0);   q9 a0 V, M% w: c3 \$ v
  13. ' D1 g5 T& }! \' k
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* l; }1 n. Z! |7 q
  15.     $dbuser = 'root';            // mysql用户名" ~( c0 u/ h  ?. t! l5 `7 e8 ^
  16.     $dbpass = 'root';          // mysql用户名密码3 p$ e. F( }! [$ b' {
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    + D, Y, {( _8 D5 f" i
  18.     if(! $conn )9 A2 @4 S7 S$ j8 |8 n# L" d
  19.     {
    * d) C9 o, s0 h" n* H
  20.         die('连接失败: ' . mysqli_error($conn));% o  a2 Y/ m/ H. s
  21.     }
    3 H- z/ P% `- @+ W% o2 {! e
  22.     // 设置编码,防止中文乱码6 q" r8 o! ~  g- b
  23.     mysqli_query($conn , "set names utf8");  }1 L7 h% V7 g! H) t7 o
  24.     mysqli_select_db( $conn, 'temp' );
    : }3 C/ t: s  q9 S6 G8 `

  25. 6 ]6 X+ L- w& R' |; G( b+ ^6 X
  26.     # mysql 锁 ( i2 p0 E# y( j4 Y( R5 p7 n' j
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 # A' K0 D1 _+ P8 [
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); ! v- s. o6 \( k3 C3 q7 [
  29.     $id = mysqli_result($rs, 0, 0); 5 U- [3 T! `- u% [3 b! Y
  30.     if($id > 0)
    - z8 q4 t7 y0 l: i- l
  31.     { " w. B* y5 b  \# j! c
  32.         --$id; ( C! Z: ]; A/ _* w( ^. S! X
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    5 `6 d1 u% h% C" K/ Z
  34.     }
    4 r5 I' u2 n0 Y0 z3 g( q9 ^. t
  35. 8 f% J! I9 T, X( t# `* q
  36.     # mysql 解锁
    4 g2 u0 s7 I1 ]7 n0 X
  37.     mysqli_query($conn , 'UNLOCK TABLES');2 R1 T7 ~) _" ]7 I  Y3 G1 A0 K
  38.     //查询解锁后的id值3 z6 ]0 B' Y- u7 E* r4 |8 a
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    7 y- u9 Q/ G1 \$ [
  40.     // while($row = mysqli_fetch_assoc($res))$ u  b: p0 e9 v# w' F7 I5 \
  41.     // {+ y0 O3 G1 n$ M  R  H
  42.     //     $id = $row['id'];
    2 j; V% T8 ?( |5 {. j" R/ ^+ m& R  B1 t
  43.     // }
    7 q. a( |0 I0 O  Q; g
  44.     // echo $id;
复制代码
2 Q+ T  m* V- y( Y: d

; }5 }3 y3 @' }$ G
1 g7 ?3 h% r1 t( Y2 B
PHP文件锁示例:
  1. /*
    % i) B1 q$ g  P& G( Y6 e
  2.     模拟秒杀活动-- 商品100件
    , B3 I, j* Q1 O& E3 u
  3.     CREATE TABLE ta
    ! ~: `- y' s: i
  4.     (
    ! I+ y- M0 \/ X
  5.         id int comment '模拟100件活动商品的数量'
    6 m# S2 a$ w) H2 \! p; c
  6.     );
    5 ^* g( L( Y$ ]% T4 E. Y
  7.     INSERT INTO ta VALUES(100);8 Q! E- I6 g3 m0 y6 c4 x
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
      L2 Q7 K  G( _1 ?
  9.      */
    9 _3 d8 h- \, M* u5 c
  10.    
    5 P' p/ v( R# |
  11.     // 关闭错误报告  p. s' U3 v8 t3 l3 N. q
  12.      error_reporting(0); 8 ]" v3 n$ {* Q

  13. 8 m; e8 x, S9 l3 A; m& E# a5 L0 v
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    7 {, K! U4 p9 u$ {1 K, r& Q
  15.     $dbuser = 'root';            // mysql用户名
    1 |! {4 B$ B( E9 J4 j( p/ m
  16.     $dbpass = 'root';          // mysql用户名密码
    & Y7 m3 [, k6 T8 d8 W
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    % D& k2 o" Q/ p9 k1 H
  18.     if(! $conn )
    . t5 n% _/ J8 v8 q3 Q" N, n+ Z& \
  19.     {
    # L; |  B( d3 Q$ S% ~
  20.         die('连接失败: ' . mysqli_error($conn));
    : S: @; m* C6 ^# O+ ]/ C7 h
  21.     }
    # b$ ^3 N0 ~/ B9 c3 R, ~7 m! G
  22.     // 设置编码,防止中文乱码  N& h5 x6 C" J- {, w( L
  23.     mysqli_query($conn , "set names utf8");$ r2 n& k2 z6 f. a: e8 ~
  24.     mysqli_select_db( $conn, 'temp' ); ; o: Y" g2 Y( ~; B/ s3 s3 w
  25. + {0 N& |5 ?% {1 N& u$ g
  26.     # php中的文件锁 - V2 P- v( L# l& M: o' r& J
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
      q" h) g  j$ d) ]0 ?8 u
  28.     flock($fp, LOCK_EX);// 排他锁 7 J! i4 Q' v* L0 I7 O- G6 t

  29. ) ?, i- h( k* F: |" Z9 ?
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    " a& d+ ~0 d1 _& b
  31.     while($row = mysqli_fetch_assoc($retval))7 W5 L% A) ^% E( Z1 ]- ^  y" h- ^
  32.     {+ l$ Q; h/ n- r1 V: X
  33.         $id =  $row['id'];8 F% i# T2 t. Y# `' ?
  34.     }9 D- q1 I' v/ T7 i8 c3 `- {) h
  35.    
    1 {9 `7 B8 b7 B
  36.     if($id > 0) , x/ U9 l. n9 E+ T5 `* w
  37.     { : m% S. B9 n% E- @8 w' @3 j
  38.         --$id;
    , b9 F# z$ Q  [6 ]
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    % Q# x+ |: f$ _0 Z) _
  40.     } . H3 |5 g) Y2 w, Y- @8 o: d
  41.     # php的文件锁,释放锁
    % s( E  ~  b* _3 g. W
  42.     flock($fp, LOCK_UN);
    $ P' g4 U3 N# v' P5 J& ~( _
  43.     fclose($fp);
    ( {# Z5 w0 d. ~, w* V

  44. 9 s2 @7 ]1 w- [- r
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    + l- ^0 t4 s/ }; H6 U# o) g
  46.     // while($row = mysqli_fetch_assoc($res))
    # e* r7 R9 o" O- o0 f
  47.     // {0 B+ ~6 K0 C5 p4 U7 u9 u6 d
  48.     //     $id = $row['id'];
    5 t/ T) J: G4 @- s0 {. S3 ^
  49.     // }
    ' F- Z1 h: k% O
  50.     // echo $id;
复制代码

) N' H0 k# K/ l8 h; I8 n
* e8 w7 U7 X- D( Z- b9 T
抢券活动实例:
  1. public function envelopeSnatching(){
    - x1 r9 d' }$ Z9 A; Q7 c
  2.         $lingqu = $_POST['type'];; g3 m8 J6 ]$ w) n- H) Z
  3.         $uid=session('u_id');//用户id
    & X9 B2 a- D3 f; u" v: |
  4.         if(!$uid){4 X2 `7 F7 b; y4 G8 P4 K. ?
  5.             $data['msg']='您没登录,请先登录!';
    / s, Q1 w- U8 T( j( e5 C
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    5 S0 ~+ ?1 ]( ?; P
  7.             $data['msg']='不在活动时间内!';
    ) X9 x7 M6 W% e- m' r  b: b
  8.         }else{
    7 W, v+ G7 E! m$ e; I' Y
  9.             $hours=date('H');//当前小时数
    / `' @' x9 H  n& D; \
  10.             if($hours > '09' || $hours > '17'){
    % z; ^6 E+ U0 s* n5 o0 s2 @
  11. 8 Q/ [3 e5 g9 ~! \
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    , l: K: L9 h; Z4 t! Y" L' i7 d; U3 }6 I
  13.                     if($lingqu == 1){
    8 B/ d1 U/ d1 c! e! l
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    3 e: z8 A! }! B" _: ]" Z
  15.                         if($hours > '09'){4 t! `$ \4 V0 F
  16.                             $num=mt_rand(25,28);//优惠券金额
    1 V4 |, m( K5 Q8 G- a# C
  17.                             $id=1;/ F) }& S( L+ ?. J
  18.                         }! Z& z% L: Q% @- q) p' f0 Y$ w5 y+ x9 @
  19.                     }else if($lingqu == 2){
    . g& L" V, ?+ G" u- k5 X( ~
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();% z* x+ _; k' d. h
  21.                         if($hours > '17'){8 z( ?) z5 A- O- r" U5 @
  22.                             $num=mt_rand(50,55);//优惠券金额/ c8 w. N0 _7 n0 |
  23.                             $id=2;9 ?: J# ?2 O* \9 d2 H  L: d
  24.                         }8 n5 k, J! Q$ I  V' c
  25.                     }* J0 c( \% G2 P' l, L
  26.                     if(!$id){
    ( V9 y6 j- W8 A# W
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    % \" }: |  X. U7 e
  28.                     }else{
    $ Q: x  W7 B" {" m. T
  29.                         if($is_lingqu){2 z0 h: B3 D5 |7 v& D/ e2 t
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';/ [8 Y. h) @$ B( k! W3 ]
  31.                         }else{
    5 N$ p" k8 P2 R. M8 |
  32.                             //锁表
    9 o: }3 S$ P4 ~
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    . U+ S7 Y7 f* }
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();- r4 i: n6 u" M" ^5 V  y: h9 X  A9 |
  35.                             if($active > 0){
    , D" j, K- w! p5 K
  36.                                 //开启事务" i& z2 o1 W9 ~& r/ G2 G! G6 ]
  37.                                 M()->execute('start transaction');
    8 R; w" }& r" j
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));; O9 C- ?& A1 D# r; r% G+ ?4 `
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));2 W1 H" S! M/ B' Z0 Q* c7 ~
  40.                                 $members_preferential    =    M('members_preferential');
    7 Q% C9 X9 R4 A, N$ b* p
  41.                                 //对应投资金额,
    % G% T2 [( f: E% J" i
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));7 S7 [& h7 D& I5 r! r4 n' C
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');) d4 _: D2 i! Z2 [
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    % v" n3 ^% s# Y" r# ^* |
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ! f  T: m! a- T  V( P" u
  46.                                 if($save && $add && $add2){3 c7 S2 ]+ b  y5 E" R" }
  47.                                     //事务提交. O3 f5 V# |7 i
  48.                                     M()->execute('commit');
    3 c  @2 o9 E5 z4 A- N
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';; |  m) [; Q' C( Q
  50.                                 }else{
    : M! x$ t4 _  R% z. H0 X) p
  51.                                     //回滚5 |$ K/ o& @! ?& h3 H" B
  52.                                     M()->execute('rollback');! x7 ^) d& L$ y- j
  53.                                     $data['msg']='未知错误!';
    # x+ I1 O7 y, D9 u! `
  54.                                 }6 `% Z6 ~- O" n$ d3 g) X
  55.                             }else{0 ?" |4 Q' j7 x% t
  56.                                 $data['msg']='红包已领完,你来晚了!';* v: n$ _8 l7 z7 o% a* ~
  57.                             }4 r9 F, L0 R/ p$ \" R
  58.                             M()->execute('UNLOCK TABLES');
    * n3 o2 u! \/ M
  59.                         }- U. O1 y/ N& L& k2 l
  60.                     }
    / _8 ^& g; c: k
  61.                 }else{' g/ _& h- T& }6 ^$ a
  62.                     $data['msg']='非法操作!';: {: O% L! k( w% g
  63.                 }
    . `1 Y2 K; J2 X5 m) b
  64.             }else{
    0 c. c. u# @+ N/ U: v
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    : n$ C# F+ p, ~- l( w: v- G: s
  66.             }5 h  Q8 v, G# H# B; f, T
  67.         }4 E$ j5 a- R" \
  68.         exit(json_encode($data));
    8 {5 E* \: B/ L4 @$ }* V9 ?. g
  69.     }
复制代码

( r# z9 I: W" I# T3 F" g: Q' M! r* O6 T4 U- |4 c  f
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2025-2-5 19:49 , Processed in 0.130837 second(s), 21 queries .

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