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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8373|回复: 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://请求的脚本
复制代码
6 l$ J; n" u5 \4 x
Mysql中的锁语法:
: g. R/ k5 [/ ~5 O& gLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
* k/ C- F( ?% H/ s0 ~5 M7 ]: A: h$ AUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表+ R7 g# U5 p: ~) h$ O# i
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞' G' _  Q9 n# t  {9 I8 ?
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :+ m8 ^9 j1 c' D3 `$ T% c
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
, Z3 ]7 H' ]" t/ u+ |# h! ~测试时,有个文件就行,叫什么名无所谓
总结:
% b7 U/ O9 D. U' _# Y5 r项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
# @% V- t0 a8 s- M. ~& ^% H$ j1. 高并发下单时,减库存量时要加锁
9 L$ X6 r( n3 F+ `2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*+ q  |$ ]# v- I1 M. z) R
  2.     模拟秒杀活动-- 商品100件
    " I4 F: B; D# D  T2 A& S
  3.     CREATE TABLE ta
    ; z$ h- b3 i# j) j: `
  4.     (, c7 C8 @, m8 d' t9 o+ V  h
  5.         id int comment '模拟100件活动商品的数量'
    " e7 \, i! r9 W. M% N+ Q3 O( S$ S. T
  6.     );! d0 p/ @# ^8 u7 A# t' q/ T/ E( v& V
  7.     INSERT INTO ta VALUES(100);
    ' p4 F$ r) j& Q1 @2 o- N- B# X
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    9 B- \& |% L5 s% c) I( a
  9.      */
    $ C6 p' Y2 C& E
  10.    
    7 m5 O( Q3 Q# k: _
  11.     // 关闭错误报告9 j3 F2 w* `) L% w, J
  12.      error_reporting(0); 5 ^6 A4 p( ]. e) ?: ~. \

  13. ( }* U, p7 C0 f
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址6 N8 o. Y; b  \; h3 h. u
  15.     $dbuser = 'root';            // mysql用户名
    / |+ C; E7 S7 E3 `! w
  16.     $dbpass = 'root';          // mysql用户名密码
    3 |3 {4 K7 B& E
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);- l: x( U' U" F. B! I$ d' A6 m# q
  18.     if(! $conn )8 `( c, }3 ]% e, i
  19.     {$ a4 h$ i1 V2 F. l) H
  20.         die('连接失败: ' . mysqli_error($conn));
    8 [2 R5 \$ m# K, z8 r4 O5 i
  21.     }3 n) J' ?  S( t& Z+ w, ?0 ?- i$ X1 x
  22.     // 设置编码,防止中文乱码" U6 F5 |- ]! Q) E
  23.     mysqli_query($conn , "set names utf8");
    7 b+ H5 ^; ~2 r0 `
  24.     mysqli_select_db( $conn, 'temp' );
    3 W% Q0 G# D- n; K, q
  25. ; l- G- d7 Z: l& L: U: A
  26.     # mysql 锁 5 g$ Z! R1 T3 \7 ?" w, }! B2 q) [: ~
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ( y9 Y+ c1 ^" I( C) k* H5 x) N! K
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); ) c" s3 M& s* j: L4 f+ g3 \
  29.     $id = mysqli_result($rs, 0, 0); 6 s& i. F3 x) d& z' O+ d
  30.     if($id > 0) ! `) S6 q; @  r, \: Q9 D# s! J
  31.     { $ m$ k# Q5 }$ ]
  32.         --$id;
    + l+ S$ n& c& D4 B' E3 R# t
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 3 C$ p3 ?8 @) N8 n
  34.     }
    ' T( b. f' j3 U, t+ r3 k) T; H+ n

  35. ' j0 v6 Y" Q8 S! {: J5 m1 |& ]2 S  r
  36.     # mysql 解锁
    ! x9 O/ w% w' p7 q. @
  37.     mysqli_query($conn , 'UNLOCK TABLES');  m  T) D3 i2 j9 a% T! e% B
  38.     //查询解锁后的id值' T1 H2 a8 ]1 g/ ~) w" A; [
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ( \4 Y) y3 ~, T' x( X* k, t& O. C/ U
  40.     // while($row = mysqli_fetch_assoc($res))1 q( l8 u" A" p
  41.     // {5 H0 H4 _- Q/ ^: k. J
  42.     //     $id = $row['id'];
    0 @, [5 e5 ^5 W; V" r" @& f+ C
  43.     // }- ]2 j* B+ _* N. r$ S/ |4 \# H
  44.     // echo $id;
复制代码

. `* H0 Z  ]: ]9 h7 }( `# E, T4 y  t4 m3 u* z1 h" r# i5 e
% l% y% z) K7 }* f9 H
PHP文件锁示例:
  1. /*
    8 Q1 |+ ], g3 }- t" x$ D
  2.     模拟秒杀活动-- 商品100件7 ^; L5 I+ E2 K  c1 I
  3.     CREATE TABLE ta
    / s! Y0 m% d" l" I! O# g
  4.     (
    , o- F% l: `1 a; f1 l
  5.         id int comment '模拟100件活动商品的数量'* N" p( s/ z  N& c1 j
  6.     );
    1 N- x0 }( P5 G# I
  7.     INSERT INTO ta VALUES(100);0 J; t: u) D2 g2 P# R7 {
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    9 K* _6 x& _1 y+ {/ U8 x
  9.      */ % A; ~. ]6 e: b* y
  10.    
    . x: ^% I. @3 r3 h# X! U
  11.     // 关闭错误报告0 `5 y: X1 {& _. H& j
  12.      error_reporting(0);
    9 W) R$ i4 |8 b2 Y
  13. ! E' ^! @: W0 T( Z3 h7 m' v
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址; m% K& x4 M$ i* L# a. q
  15.     $dbuser = 'root';            // mysql用户名
    ' ~" h3 m* W  Y' X0 ~5 a
  16.     $dbpass = 'root';          // mysql用户名密码
    # o& j: Y2 O, ^# H/ X: t
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    9 E9 ^4 G/ O: ~
  18.     if(! $conn )
    , }3 g4 d& _( v: T  B* o5 B
  19.     {8 _( B' F; t& a+ l  k, s2 m
  20.         die('连接失败: ' . mysqli_error($conn));
    $ j0 i3 W  q5 s/ s. p
  21.     }" t3 a/ \5 F+ J) H  C$ e* k+ B
  22.     // 设置编码,防止中文乱码$ ?. d4 y, G+ E  M% k, T; x; n
  23.     mysqli_query($conn , "set names utf8");( a8 p) o( F3 t9 n: @5 a6 n2 h
  24.     mysqli_select_db( $conn, 'temp' ); / I; Z& a9 u8 }6 c" m6 X* l

  25. 3 v+ x# q% I# b1 S/ ]) i% `5 I
  26.     # php中的文件锁
    4 p2 j" H+ z$ r
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    * ]1 ?3 H) [1 ]& N! _. ?+ \% l
  28.     flock($fp, LOCK_EX);// 排他锁
    " ]! ~% O) r0 ?4 j$ N0 Z
  29. 9 A( O3 F( o+ t8 _2 y6 g( I
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    + V$ Q5 n4 a- n1 F/ @
  31.     while($row = mysqli_fetch_assoc($retval))
    5 i# w8 B7 h" m
  32.     {
    ( _; P# ?! B, d8 e4 r6 ^) k8 R
  33.         $id =  $row['id'];
    ' _- m, h  d9 \9 y) y2 _
  34.     }! r$ c/ m  x: c$ f5 ?
  35.    
    ( W" F& X3 N3 ^$ p' s- p8 l/ {
  36.     if($id > 0) 2 p% ^1 S+ U- ^; {0 x
  37.     { 9 l  k: P2 t7 d  V
  38.         --$id;
    6 p- m" d+ j, i1 F9 M
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    ) J5 M# M6 {/ @. b4 Q' J
  40.     } 4 T- ^7 \) n! _! Y
  41.     # php的文件锁,释放锁
    ) ^2 {4 A9 F/ C" h4 @
  42.     flock($fp, LOCK_UN);   k* k7 H, h+ W: M( i2 J, \3 H0 j
  43.     fclose($fp);5 O; g* ~8 ]# o: M0 z

  44. . _6 V2 j, Q8 _8 H
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');4 B: C: j; k; _8 ]
  46.     // while($row = mysqli_fetch_assoc($res))! V/ w8 S8 L: u" e% V% F+ i$ Q
  47.     // {6 y; E9 t1 T' q8 M" |
  48.     //     $id = $row['id'];  ]; R" P1 T8 ~
  49.     // }  [* q9 l" }9 f7 U
  50.     // echo $id;
复制代码
* v  k7 e9 [7 t# d& X6 f  q' D* f& ~
+ @# H, O5 w  b
抢券活动实例:
  1. public function envelopeSnatching(){
    ( O( c- r7 {/ @! [5 I
  2.         $lingqu = $_POST['type'];
    ; o/ T: y4 G! D; t# e
  3.         $uid=session('u_id');//用户id6 C( l( H+ o9 I" _( s3 y
  4.         if(!$uid){
    ! C2 d, b/ ?( `# F- N4 m5 ^$ q' g  Q
  5.             $data['msg']='您没登录,请先登录!';* g* _5 n$ r: a0 r2 E3 X( G8 m7 e: D( p  I$ ?
  6.         }else if(date('Y-m-d') != '2017-12-12'){+ f6 ^9 J& R6 J# o' }
  7.             $data['msg']='不在活动时间内!';
    , f+ o' q/ R0 I/ x/ Q% a
  8.         }else{& R/ s( g- s5 n. }! o
  9.             $hours=date('H');//当前小时数
    6 d  C. A! o( U' t: p4 ^) F7 p. R
  10.             if($hours > '09' || $hours > '17'){- `9 M  B% ]1 x7 q4 A
  11. # j3 i9 j8 {, d& l7 u) j% F
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    4 o1 ~( _* V( B! I& ~6 n) ^
  13.                     if($lingqu == 1){
    9 _- w% g! i) U7 G* v
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    3 q' k( f$ Q6 @5 Y5 q* k
  15.                         if($hours > '09'){
    7 q$ @* a- w, Z- D, g" d( v5 N
  16.                             $num=mt_rand(25,28);//优惠券金额- A$ U/ [8 y$ F' K( P
  17.                             $id=1;
    6 a- e( H$ y) o# ?& O! e1 k7 J% [0 D
  18.                         }3 s5 Q  q$ [; E( F5 x  k
  19.                     }else if($lingqu == 2){+ I+ ~" L( }0 \3 T8 ]. u5 K; `0 x3 ~
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
      s$ \/ R3 \! J$ m3 p
  21.                         if($hours > '17'){
    7 A- x  l4 H( t* l: U7 @6 |
  22.                             $num=mt_rand(50,55);//优惠券金额0 S5 c6 A. S# t, T2 Q
  23.                             $id=2;9 n) b$ h6 O7 P4 H7 S5 @7 I% ?4 u
  24.                         }
    7 k# r1 q! U( n
  25.                     }( v, x: z8 \* T- s, y: x8 w, ]# ]
  26.                     if(!$id){
    $ |! R) |+ ^" @9 n1 m$ o) A3 H1 B5 A" I
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    + V& Q+ G7 y* k6 U: e" F
  28.                     }else{' ]+ `% d( L' I2 x' @
  29.                         if($is_lingqu){- D2 N3 X! h; O
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';- |1 R9 r' v% _
  31.                         }else{6 r$ j, ]5 ~3 L& B1 D
  32.                             //锁表
    8 e# M7 {  Q) r% O- P. i- x
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');( h4 o  k& x. r# O; k9 G6 P
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();* O4 v8 {: I: M( Y- u
  35.                             if($active > 0){
    1 B0 O/ D) H2 j7 [
  36.                                 //开启事务8 G/ F5 v9 P6 X, r
  37.                                 M()->execute('start transaction');0 m: [+ d4 y1 j1 D
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    5 L( U/ {. A5 ~% o7 X& O7 G
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));( I7 K! F* ~6 p
  40.                                 $members_preferential    =    M('members_preferential');! q0 \% p0 g) ]) O0 A) V* ?) r
  41.                                 //对应投资金额,3 e! B8 O+ b; @6 L! i+ u5 Q% m
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));1 c9 \5 K* Y9 h, s. s8 A9 ]6 H
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');( w5 I# h' v) n4 {& F0 R- A/ I
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    5 g& n+ n. {! C* @
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券. ^: w, h$ J+ X3 t( L
  46.                                 if($save && $add && $add2){3 {2 X* O2 e8 `/ i5 g' i, k3 r2 Z
  47.                                     //事务提交
    + x/ E* S# b# X# W/ O  @1 V
  48.                                     M()->execute('commit');
    4 J" D( q: a) L* [0 B( |0 S( A* F
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    + E( b4 Z* }4 a8 q8 e0 Q
  50.                                 }else{( a1 t, z% `- Q
  51.                                     //回滚$ D& P* c' [* P: e( _# @
  52.                                     M()->execute('rollback');
    ) h8 C* q, b: {; C/ n
  53.                                     $data['msg']='未知错误!';# v4 {6 M# T" _$ Z  v" n
  54.                                 }
    - n# k$ q2 P. ?
  55.                             }else{
    : N( @& m# ~% Q& |; n
  56.                                 $data['msg']='红包已领完,你来晚了!';/ G2 h9 l3 ~3 z+ }
  57.                             }
    2 o8 @+ c# t* z# H9 H7 ~
  58.                             M()->execute('UNLOCK TABLES');, w" g9 X2 Q/ Q, j( _3 x) f: C
  59.                         }7 F& r, y3 F! V% K+ g! _
  60.                     }. j) w* g1 G3 H/ x6 e
  61.                 }else{
    . m5 ?6 J& Q/ H* x
  62.                     $data['msg']='非法操作!';5 X4 g" O4 |; I/ ?1 @
  63.                 }: Q# {6 I. W# i% a' j& _: c7 Q2 S+ y
  64.             }else{( W# y% f& ?3 t. l; ]5 c
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';3 `) ^8 [8 r+ r1 `9 p
  66.             }2 {  e. M" u' i$ a- P1 ~
  67.         }
    : N; Y5 n# m& s5 r1 H
  68.         exit(json_encode($data));  F8 R) X5 q$ L3 V
  69.     }
复制代码
* \6 {1 _2 ^8 Q4 B- V' |5 A$ a

; m! P! r. t7 n
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 20:01 , Processed in 0.055266 second(s), 19 queries .

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