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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

3 X+ D$ x6 o% z& [( [5 }- F
Mysql中的锁语法:0 j5 V2 e' @( Q+ ^8 k, Y
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】( i* X0 O5 ?; h. V7 O  ]: U: Z
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
& n; W% n' R1 M/ R0 XWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞( \- w$ G( S- F) V$ U5 \
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
5 g6 U8 P& X0 p8 T+ V文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。# I$ g/ z% @: J5 U6 p6 m- `8 D
测试时,有个文件就行,叫什么名无所谓
总结:
9 d% `2 \6 F8 N( Z项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
3 J. u* \# _0 A3 g2 {3 q9 V1. 高并发下单时,减库存量时要加锁
% b: e0 f0 @8 s4 H9 M2 g2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    , p3 K7 R1 w, e0 n
  2.     模拟秒杀活动-- 商品100件
    ( D' a: K( i: T( J# ~! W
  3.     CREATE TABLE ta$ e& `" `- H2 s: `
  4.     (4 n5 M) a$ ?* w1 P7 Q: y
  5.         id int comment '模拟100件活动商品的数量'
    1 f3 Q  j3 A1 V/ B! x4 i
  6.     );
    3 B6 ~/ m" I6 V0 G9 W5 w8 F  l; d. k
  7.     INSERT INTO ta VALUES(100);. F. \  p9 M  P; {; W& @
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    : O! t' E1 j( Z: w
  9.      */
    1 |8 t) L1 B( r( c6 m
  10.     ' C. k8 h  J; i0 i9 l
  11.     // 关闭错误报告5 C7 k7 b* r- z- W
  12.      error_reporting(0); 2 b' H1 ]) P: C

  13. 7 E% e4 F  @2 [+ H) Z
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址6 M* A0 v6 c; w. ]5 h
  15.     $dbuser = 'root';            // mysql用户名
    ' ~+ m# x; ~3 w! U0 x( B- Y3 q
  16.     $dbpass = 'root';          // mysql用户名密码) K" J8 f0 D2 i+ ?9 m
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);2 L" z8 U6 \2 m" l* b4 e( l* q5 E
  18.     if(! $conn )
    ! t# P% r, j: F# m* s
  19.     {! Z+ n9 {* p  e+ r- d, J
  20.         die('连接失败: ' . mysqli_error($conn));  k2 W5 g: k+ p' W2 @
  21.     }7 Q% w- p8 I  `/ j0 J# d; o& v
  22.     // 设置编码,防止中文乱码
    0 s: H, g4 S( ~1 o: B% W
  23.     mysqli_query($conn , "set names utf8");5 G  x3 Y, O8 f: U& b# G: E
  24.     mysqli_select_db( $conn, 'temp' ); . u/ X# j/ }- `. g. ?
  25. 5 s& }- ?; a$ W# q& r& g" e
  26.     # mysql 锁
    ' O, P3 ^3 v1 A4 n4 w1 y( j7 C5 q) E
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    6 D. T) {) r5 \( u+ w3 V
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 5 x5 b6 O, [/ a& g
  29.     $id = mysqli_result($rs, 0, 0);
    " Y  ]7 w' N! X, h/ C
  30.     if($id > 0)
    2 {  Y. n+ ?# k6 C
  31.     {
    ' \- a- ?9 p5 X+ h' t3 h
  32.         --$id; / k& N6 |8 g- d% }
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); % Q' c2 I& h! B1 a' ~: S6 Z* d; `
  34.     }
    ' c5 ~# j) e  E' a3 N0 s+ x
  35. , c( L8 V' @- D; a+ _8 t& P4 G
  36.     # mysql 解锁 5 K' M1 m0 Q" p7 u
  37.     mysqli_query($conn , 'UNLOCK TABLES');( e8 ?) D7 }$ J; s9 J& i' l! _
  38.     //查询解锁后的id值! M5 ~' g+ k7 x' ~* w) Y) _
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    : o# B1 t. Z" X' ]5 b
  40.     // while($row = mysqli_fetch_assoc($res))
    % o  J  @7 m) {( D# G# h1 [' F
  41.     // {1 i$ s& V4 w. A7 L5 }2 G9 G' y( p
  42.     //     $id = $row['id'];
    ! ^( B% ^( c. D, }4 L
  43.     // }
    5 w: ~. B- }& x2 k2 J
  44.     // echo $id;
复制代码

# q) Y% m0 a" J/ g
: H2 M) B  s" E' c0 @

8 X6 _- n  |- X% k* r
PHP文件锁示例:
  1. /*( @  M, P: l* I4 h9 A& h  Y
  2.     模拟秒杀活动-- 商品100件0 _; [: R7 `  g  y  n
  3.     CREATE TABLE ta
    / t9 X& r% ]. v/ y/ J. d+ u2 |! D
  4.     (
    % u: T- s( b: ?' Y$ Y
  5.         id int comment '模拟100件活动商品的数量': N3 P+ Y8 E' E8 Z
  6.     );) I2 r" j- T: M
  7.     INSERT INTO ta VALUES(100);2 A5 U3 r4 P3 N* ^
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件0 X; D6 Z. }8 b
  9.      */ ' ]; X. X2 B6 j5 B- t/ m3 K4 g" j
  10.     8 I3 I+ b5 x% a, o0 q$ \% t
  11.     // 关闭错误报告/ ~  s2 G  v2 |6 l% e
  12.      error_reporting(0);
    ) a/ {( e5 Z0 J! O" L

  13. 0 \- E: E3 T$ J( g) I
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    2 k: \7 f) i* D  S1 l4 P) ?
  15.     $dbuser = 'root';            // mysql用户名4 }6 r* s' ?# q( n
  16.     $dbpass = 'root';          // mysql用户名密码! A+ y5 t7 r) l
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    0 c  x6 I4 s8 C: U" o5 i2 s
  18.     if(! $conn )
    : G0 d8 e5 K7 V2 K9 O; R# T! U
  19.     {
    ' t" S( e9 h4 _# ]& Y7 c
  20.         die('连接失败: ' . mysqli_error($conn));
    8 S) Z3 ?) s  a/ U
  21.     }+ n( v2 _) M" k! c% m0 u
  22.     // 设置编码,防止中文乱码
    8 a0 w, C! s  i5 o$ M" X( O
  23.     mysqli_query($conn , "set names utf8");3 f6 g" f+ D3 k0 t
  24.     mysqli_select_db( $conn, 'temp' ); 2 L, g) s1 l. U: I; J

  25. 7 G" t. i5 i8 @  p
  26.     # php中的文件锁
    / L# O$ z& g8 B" A# C
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    9 c% R1 x# r# Q& t# `, f
  28.     flock($fp, LOCK_EX);// 排他锁
    1 p" L- [6 N0 ]$ h3 Q' m9 k
  29. 1 a; P) a9 f+ l; i0 T
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); % V6 q$ \6 S( X
  31.     while($row = mysqli_fetch_assoc($retval))
    5 D) t0 ~( c* s7 k/ K
  32.     {
    " l( v$ M4 c2 p& c; t' E
  33.         $id =  $row['id'];" E8 @9 o9 H* Y9 i# x" V6 }5 Y
  34.     }
    ; t2 }3 s% [8 {. q7 N
  35.     ' Z) Z5 `8 C: o2 r3 x: j( N) ?* L7 \
  36.     if($id > 0)
    $ o9 U) t  }! _2 S" ?
  37.     {
    ! M$ i9 c- s4 X6 D* a+ o
  38.         --$id; 1 B' c' [% {7 E1 u( J! v5 n) w; O
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    ! N. p& ]1 y, ?/ ?
  40.     }
    9 r5 P8 v% H7 \3 j: q+ y1 W  H
  41.     # php的文件锁,释放锁 . J2 d, c/ U( S  q( [( [
  42.     flock($fp, LOCK_UN);
    6 a; z% H3 J* O& s. q+ D4 A
  43.     fclose($fp);
    7 D1 {. u( N7 J3 B5 i" r
  44. 9 C% w* o) u0 ^2 E& h
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ) ^% ]) o5 |5 W4 v; G  c
  46.     // while($row = mysqli_fetch_assoc($res))7 N( F% s# C* y3 T7 Q8 r
  47.     // {
    . g5 L# c! L2 U% n
  48.     //     $id = $row['id'];
    6 r- P1 X/ T5 @3 J* ?; C0 }0 L
  49.     // }2 r! d1 ?& n' e& v& @( h; O
  50.     // echo $id;
复制代码
. f  ]7 E) o$ v# U! l1 \9 F# g

0 @* T) y* R8 I. O$ z2 @
抢券活动实例:
  1. public function envelopeSnatching(){
    ( u/ H' l8 B$ K8 c
  2.         $lingqu = $_POST['type'];
    5 I. D* _" `9 n+ M9 {
  3.         $uid=session('u_id');//用户id" {$ v9 o3 M& Y; a; \
  4.         if(!$uid){1 q' ]# r+ @* a- D; R4 Z
  5.             $data['msg']='您没登录,请先登录!';
    ' v* B6 ]( v6 q9 U( B5 q2 k* O
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    " J$ [9 |4 S% i0 W  W" {' K. _$ C
  7.             $data['msg']='不在活动时间内!';
    7 r& X8 A  I& t% Z& k
  8.         }else{
    9 G# d0 h/ l" e
  9.             $hours=date('H');//当前小时数+ Q* k) T* q7 i& n, X) Z' c
  10.             if($hours > '09' || $hours > '17'){
    9 W2 V* V+ Y3 E$ m8 H
  11. 9 K; R. ~8 E% |
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    # I& p/ D+ O! w5 K
  13.                     if($lingqu == 1){: }) N! Z$ D5 z! P0 y, t7 a( _* ^
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    9 U  q. q& m, x: l2 a
  15.                         if($hours > '09'){
    * ^* e8 ]- ^$ P  B0 u
  16.                             $num=mt_rand(25,28);//优惠券金额
    1 v) F* f5 c$ H- Z$ f3 E. T9 P7 W
  17.                             $id=1;* f" \5 u0 i7 Q4 c. @8 N
  18.                         }
    9 s# Q) q. u: @0 a
  19.                     }else if($lingqu == 2){! W8 j/ S; b; w8 Z: P2 m9 z6 O
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();7 H5 C4 H6 C# o* {9 n2 t; |$ ^
  21.                         if($hours > '17'){
    / o0 H! P  g  b2 q  A
  22.                             $num=mt_rand(50,55);//优惠券金额
    $ b5 X, c2 `& C5 l* h
  23.                             $id=2;. p+ g2 \5 f9 I) L( A
  24.                         }
    ' P) O% a0 y$ B, O+ i* r5 z/ j
  25.                     }& H7 m, p- o! N2 b5 _9 l. e
  26.                     if(!$id){
    - A2 i  V6 S" q7 t9 C
  27.                         $data['msg']='时间还没到,晚点再来吧。';7 e' `9 N3 F& K$ Q7 f, H9 k0 \
  28.                     }else{
    , I' I# z0 L8 ^$ v
  29.                         if($is_lingqu){
    , H6 s4 F* w# d/ U
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    " ]7 ^2 S* g. s
  31.                         }else{; I1 W/ W" v, q& b# P4 O
  32.                             //锁表
    + A' V) ]5 L9 K, N) |7 r" ~
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    : A  M0 }9 {" v# U
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();2 O% j- E+ N$ r# z* u; H8 N
  35.                             if($active > 0){
      ?5 f7 [# Q+ z9 s' p
  36.                                 //开启事务4 m, X% _% Z+ ?9 \3 u5 e
  37.                                 M()->execute('start transaction');
    $ P& r- s( P) G* |/ l. T
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    2 J5 C: d. z( e! X8 A) C
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    , r$ q( x" y2 d4 Q1 @9 w
  40.                                 $members_preferential    =    M('members_preferential');
    . H. y5 M8 e0 ^$ T8 w6 _
  41.                                 //对应投资金额,! `) p2 `7 c$ }( q; @7 h5 F
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));7 Y1 L. ^" }0 |1 f# x8 j( V2 j, B/ B
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    " d! p# f5 D/ E: l5 y
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间' y) i; v) x0 L7 {
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    " z  y/ R' W4 R6 V/ L2 i  p
  46.                                 if($save && $add && $add2){
    1 ?  u* D9 d, I
  47.                                     //事务提交! l; [4 }, b; M
  48.                                     M()->execute('commit');
    6 a! f# ]1 V9 b5 v+ q  J( g
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    : K% Y1 D1 _# Y$ ?, w8 V
  50.                                 }else{  M9 b' T0 R7 |4 g
  51.                                     //回滚
    5 A8 V4 F) g" p+ G, ?- D
  52.                                     M()->execute('rollback');1 z& e1 p* m/ L! Z) k
  53.                                     $data['msg']='未知错误!';
    . z! ~" X" H, X. O2 r
  54.                                 }
    2 z' ]4 }# w" N1 i
  55.                             }else{6 c: D' K# u/ p" c" N
  56.                                 $data['msg']='红包已领完,你来晚了!';# v7 @9 b+ @- A2 ^
  57.                             }) q6 z: Z/ F+ ^7 b
  58.                             M()->execute('UNLOCK TABLES');
    , e3 [6 ~' y" J  d* i" x, [
  59.                         }6 a7 `( m7 f1 T6 b" m! @# C1 r2 L
  60.                     }* {& K- A) L" I2 ^# \7 \& g
  61.                 }else{
    6 Q% I$ m, \+ _# a# u3 k8 ?) O3 y
  62.                     $data['msg']='非法操作!';
    $ ?- [  |( Y/ p
  63.                 }
    : R8 T- L3 Y2 M) [+ y
  64.             }else{
    0 B) @- d3 Z5 g$ M% ?! v& ~
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    / C- T( m) r4 b" e2 `8 M( P) l
  66.             }" R; l5 ~! n9 |7 A: i
  67.         }
    2 w/ P, r4 X! p' y/ r/ j
  68.         exit(json_encode($data));, r. k* G& Q; B( \
  69.     }
复制代码

# ~" @2 b. @6 u2 ?# U& i' Q0 U0 ^- R+ W
0 Q: O8 \" h0 p2 m
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 18:03 , Processed in 0.148483 second(s), 19 queries .

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