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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 4000|回复: 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://请求的脚本
复制代码
, n' v, P3 n8 ]7 m: ~
Mysql中的锁语法:9 f2 X/ A* d* G6 E% ~7 H
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
4 B$ x* v. ?5 u9 Q+ bUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
7 U! S. A% |: X, U* p7 uWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
) Q9 C) \) V( }注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :( s1 p& y0 \/ u9 h
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。: c8 z4 B; ?- p/ ~. K% _
测试时,有个文件就行,叫什么名无所谓
总结:
, u" X/ X/ [0 C) N5 d/ ]项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
! O, c$ H  e; ~7 U1. 高并发下单时,减库存量时要加锁
  T+ w$ ~& }! J2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    / C4 V# }) R% \, X* N: d
  2.     模拟秒杀活动-- 商品100件. _! s6 @* O9 f6 W9 K
  3.     CREATE TABLE ta
    2 Q. Z6 j. F1 u, ]* X4 f8 l
  4.     (
    2 F7 O% {  Q. F2 K8 f% _1 S, G
  5.         id int comment '模拟100件活动商品的数量': f. A6 ^/ D4 R& m, Z6 S; a2 v+ ~
  6.     );
    ' V% Y1 ?/ |# ?, w+ J0 B* [
  7.     INSERT INTO ta VALUES(100);
    ' _6 P8 M2 |/ a% @
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    8 s: N5 R+ @% i5 m$ K7 a0 Q
  9.      */ 3 I3 G. ]* H* M3 o9 G
  10.     : O7 f% p8 v! C- H$ {
  11.     // 关闭错误报告& F% v3 e/ ~4 }- W
  12.      error_reporting(0); . `1 R% o( `- h2 \" d
  13. , N: v9 y# r5 F1 C1 Y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    # E. h$ w4 W- X. t. _( Y- `
  15.     $dbuser = 'root';            // mysql用户名
    ( B  r) i2 o' K) I$ K! c+ B5 M, i4 L7 G
  16.     $dbpass = 'root';          // mysql用户名密码
      D6 Q# `# Y! i+ R6 X
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);$ t5 E, m- ]/ p5 }; W6 H" {' O
  18.     if(! $conn )% i/ o2 e" z9 m; v
  19.     {2 K6 u3 }5 ?! s* L
  20.         die('连接失败: ' . mysqli_error($conn));. y" m5 c+ B  f) Q( G7 ]
  21.     }" l9 r$ j' u5 S- m3 v
  22.     // 设置编码,防止中文乱码( @3 G- ]- ~/ f( e) F1 ]) q9 f
  23.     mysqli_query($conn , "set names utf8");
    % B) \9 B) b" x; [" r; ^& u2 k% _
  24.     mysqli_select_db( $conn, 'temp' );
    " K& t0 G5 }$ _7 d/ H2 ~1 L
  25. ( l& A& K' I5 j: n- z4 k
  26.     # mysql 锁 0 ~$ K* U. J. G. {  ~
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    & O/ h3 I* L8 Z) v1 o
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 6 {' a8 H$ r% y& Y8 b7 ]
  29.     $id = mysqli_result($rs, 0, 0);
    " U7 _# O/ }* F. c; \) m% J1 @( z
  30.     if($id > 0)   p; Y! f+ A. Q
  31.     { # U  |! }4 N* I2 d' p% h) b
  32.         --$id;
    " h% ^9 Y( P8 W6 I1 y
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 7 u: r/ R3 D/ {- s, @4 M4 f
  34.     }
    ( l' d$ [8 p& K
  35. " J; w2 \- j7 `7 x6 V( a1 F, k
  36.     # mysql 解锁
    + z8 S4 k6 A! k5 u! D, T. k
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    : P( U( H# T* Q# i! o: N
  38.     //查询解锁后的id值5 i5 q+ p- q8 `7 _" [, G9 b/ y
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');9 r- a5 \# Q4 r2 k1 q" k
  40.     // while($row = mysqli_fetch_assoc($res))! b: m* [  ]( v
  41.     // {& c. w+ B3 V0 l3 K. ]
  42.     //     $id = $row['id'];8 ?& D( c4 o' o) c1 `5 g
  43.     // }
    $ |2 ]. ^1 Y1 Z  g
  44.     // echo $id;
复制代码

8 ?; V/ d2 ]2 `, d. u6 w' @& q! e# ]1 R7 k, ^
: s( n- N' `4 G" z
PHP文件锁示例:
  1. /*
    4 O$ h( s4 N7 P" A- b/ T" ~
  2.     模拟秒杀活动-- 商品100件( F& S) Q; ^( O# M& N) W
  3.     CREATE TABLE ta5 m' i  ?3 H0 r2 A6 G
  4.     (
    $ ~& k# J1 {! C9 [5 Q% S* N
  5.         id int comment '模拟100件活动商品的数量'9 S/ |# F; o- G+ k
  6.     );
    # d; G# x- b: K! U0 c
  7.     INSERT INTO ta VALUES(100);$ p' V1 r/ a# e* e1 r; h
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    * Y! f) }2 Z7 y) F3 B, R1 s. `
  9.      */
    / T; K5 e! [7 c2 E2 m( Y
  10.    
    7 f1 {) o! `$ c
  11.     // 关闭错误报告. c4 k; i1 C3 z5 I, M/ a8 d
  12.      error_reporting(0); , b& h8 p- \0 Y) E' r) S
  13. ! C$ I- n9 z  E1 e' L" L3 b& r
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ( A) G  H+ M5 B5 `+ ]
  15.     $dbuser = 'root';            // mysql用户名
    - }* \9 y  ~. }) c4 ~) e
  16.     $dbpass = 'root';          // mysql用户名密码# D7 Q! H1 C, I& e
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);  \/ P# ~% E7 N' T' s
  18.     if(! $conn )! T) _9 U, E- l; z4 R1 n6 m
  19.     {
    ! T6 P" k6 [+ K, J
  20.         die('连接失败: ' . mysqli_error($conn));
    + e% U/ Z  H% h/ n
  21.     }
    ; l- h" a. b. A9 ?
  22.     // 设置编码,防止中文乱码6 J+ U- |' Y; A) q: A
  23.     mysqli_query($conn , "set names utf8");
    ! Q3 q' M+ u# r8 j5 {' V$ |
  24.     mysqli_select_db( $conn, 'temp' ); , P! i, s" {/ w. }' e8 M

  25. 5 a  w* N( f4 n& l2 q+ f
  26.     # php中的文件锁 2 p5 H; {* [& c4 T" K$ j
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可   b+ V. ?$ v: U3 w# O2 n' k6 ^: J
  28.     flock($fp, LOCK_EX);// 排他锁
    2 D* s1 C; T- e# S

  29. 2 Z( R0 B8 a+ k. I
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ; A! b- d6 b! a. X9 ^9 g" e% ~0 R
  31.     while($row = mysqli_fetch_assoc($retval))
    1 T9 |4 _9 ]4 |0 k
  32.     {, }9 u( c$ k5 y/ D6 B* k7 ~4 i+ m4 X
  33.         $id =  $row['id'];. a3 |3 O$ }1 |' m- W5 K' L* u5 l
  34.     }
    $ E1 S. O* ?" \- A) U
  35.    
    7 a4 _: }4 H6 t
  36.     if($id > 0)
    / n. R4 l0 D. E% f
  37.     { 4 _& i5 W7 O" O( m" E
  38.         --$id; ' o2 O; W, v7 E: J; h
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); " S1 s- z& ~3 K0 T& B) ^
  40.     } 4 }. u# j: m& @; t
  41.     # php的文件锁,释放锁
    & [7 I8 g8 ]5 \  F! i
  42.     flock($fp, LOCK_UN);
    6 h& r4 Y8 M3 s5 [! i' [  I
  43.     fclose($fp);7 O! S, `2 Y3 M* d7 }# `

  44. 4 l) h" }! v% ]# i& y
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');2 _$ w6 D  X9 |8 B! f) Z4 X
  46.     // while($row = mysqli_fetch_assoc($res))/ u5 ~3 v: q! K0 p- d
  47.     // {* q+ W7 I& W0 v* |3 a
  48.     //     $id = $row['id'];6 t9 n6 G+ `$ Y6 t6 }  e% [
  49.     // }
    % F' M# P: ^& [! V9 n
  50.     // echo $id;
复制代码
' A/ t$ S$ j0 N0 Y+ ~
7 x% q: k, l1 L2 v' _2 r7 K0 m7 O
抢券活动实例:
  1. public function envelopeSnatching(){
    2 C8 D5 V3 H& G
  2.         $lingqu = $_POST['type'];
    7 z6 h' q, C! p9 q) N
  3.         $uid=session('u_id');//用户id$ [1 @8 p; i& {# A
  4.         if(!$uid){
    ) X/ n; D3 P/ ]6 e
  5.             $data['msg']='您没登录,请先登录!';2 _2 X, v/ @) ]% M0 K0 ~
  6.         }else if(date('Y-m-d') != '2017-12-12'){. M$ `$ ]+ g9 M- [- K8 R. ~
  7.             $data['msg']='不在活动时间内!';4 @( c5 C& a$ W( r# r4 c2 J
  8.         }else{; S/ C/ q! R. y% j
  9.             $hours=date('H');//当前小时数
    - |5 I8 o: L: s; ]% p# y
  10.             if($hours > '09' || $hours > '17'){
    8 t) Y, i( W* O' }/ P
  11. " [; N' I% t6 i5 \; B* ^2 c
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    0 I" V4 z) i9 U7 O$ T4 `, ~8 v
  13.                     if($lingqu == 1){& [& a1 A% I4 b# n
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过/ W: N, e; I5 m
  15.                         if($hours > '09'){
    , ?0 u" ]9 r2 B
  16.                             $num=mt_rand(25,28);//优惠券金额$ {5 k0 K0 Q% X& x. z
  17.                             $id=1;
    + \3 t/ T* n9 c! f; z6 P1 l9 Q
  18.                         }3 S, A/ ]) u6 t* b/ i' ?
  19.                     }else if($lingqu == 2){& @. a+ `; D8 {" w/ M8 Q7 u
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();! y$ L& j& S9 f9 l7 T1 z7 B1 I
  21.                         if($hours > '17'){
    0 R9 R: a  Q' t6 d" f$ ~
  22.                             $num=mt_rand(50,55);//优惠券金额
    % y5 Z. B- p6 @% e1 g$ p; c- L' P
  23.                             $id=2;' s* a$ j/ r. L0 F4 w
  24.                         }
    ( {/ J, N6 [* M* Y& c) P- v
  25.                     }" |3 ^4 u, j- p! ^( N
  26.                     if(!$id){
    - h/ F! ^  v7 t7 y4 H- o, W! l0 Q- q
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    . _( e- H0 ]; r" |
  28.                     }else{6 s, N0 g1 A  s5 g0 ~  K5 `4 R
  29.                         if($is_lingqu){
    * Y, ^& h3 W! g( F
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    . S2 V& L" z( Y9 y
  31.                         }else{7 G# T( y7 t, [9 t' h& |4 D2 F! \
  32.                             //锁表! l! ?+ O3 ?: r0 R
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    - H1 }/ ?( s4 w! Z: {7 d: s; N* b
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
      g4 R+ i! e1 M- x
  35.                             if($active > 0){0 X) `% F5 i2 F# ^0 D
  36.                                 //开启事务/ \7 W  O1 f$ @0 e4 G: f9 r
  37.                                 M()->execute('start transaction');% ?1 ?- K) L0 r+ f4 m
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    1 o5 H' o# {+ `' s0 Q2 I2 ?4 m
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    . y* t- ^/ d0 `+ E. J" C
  40.                                 $members_preferential    =    M('members_preferential');
    ( J2 G9 H( t: B9 p& J- F) f
  41.                                 //对应投资金额,2 Z1 q8 p; U0 l1 _  [
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));, f- O9 y' b/ O. O6 N
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');( D$ }$ g7 ~6 K. a( {3 i# C* e4 t2 L
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间: ]  Q! ^( i/ u2 ?
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券0 _9 ~7 J2 T0 t% C8 U
  46.                                 if($save && $add && $add2){
    : ~2 E* ?6 w! @: S
  47.                                     //事务提交1 q  h4 \& Q( a) |' Y+ y+ t
  48.                                     M()->execute('commit');
    * q, l  [# P. c2 `) r( r: `: k
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';3 m3 G  y" n5 ]0 _
  50.                                 }else{
    5 c; b2 h! I. e- Q- G& e9 c
  51.                                     //回滚
    7 K: O5 k) _. @. ]0 I' K# ], S
  52.                                     M()->execute('rollback');0 m& W( R2 Q4 f! _
  53.                                     $data['msg']='未知错误!';/ {: T/ o- A" T) z' N0 @  E
  54.                                 }
    # z' `4 e" F! t* z' b( _
  55.                             }else{
    % d. J8 I$ V0 |2 s  h
  56.                                 $data['msg']='红包已领完,你来晚了!';
    5 V9 M7 Q  H/ z& k  a
  57.                             }5 e" a5 c/ G/ y( B: c
  58.                             M()->execute('UNLOCK TABLES');
    ( \- w& K: q" h
  59.                         }
    ! ^  i7 \6 ^: T3 F# G
  60.                     }
    % Q2 ], K7 H9 h. e; r3 h
  61.                 }else{
    5 F5 [4 b8 N( \/ B" p, s
  62.                     $data['msg']='非法操作!';
    / H3 q9 X- z9 _0 y7 U# }
  63.                 }1 ]; _6 t' D7 T. H+ T' C2 r: i  z
  64.             }else{7 ^" R4 p. j: q4 N- X! i. g. Z- G
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';1 z, V( Q# F( h% v8 v; \
  66.             }
    - ^9 g2 L/ s3 U  {% T3 k$ S
  67.         }. R! _* F! h0 X% C( D
  68.         exit(json_encode($data));
    # e0 ?0 o8 Q/ V8 e5 H& v
  69.     }
复制代码
- X5 {3 p& U; l3 B; {

. _4 a6 x8 P4 u3 M
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 18:08 , Processed in 0.155168 second(s), 20 queries .

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