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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

! r8 w7 i1 l: \4 k
Mysql中的锁语法:* E+ L$ ^! [8 {* N% x# r+ X
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
$ K1 B' ~$ f1 x- oUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表, d7 k* B( M9 g/ [
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞; q) n3 k( v( u1 E
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :4 F* C1 u  \' S% E( V4 U
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。0 }1 p# c; r. ^
测试时,有个文件就行,叫什么名无所谓
总结:
: V( B2 k4 E- t项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
# Z; ~  ]1 G: B" n: r/ \# |( \1. 高并发下单时,减库存量时要加锁/ c. Q- [4 ~2 n, Y* L) J( g: }
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    0 V$ y: U4 w+ m  V" N6 B+ f
  2.     模拟秒杀活动-- 商品100件
    6 s) i. o! q$ |$ `! N4 J
  3.     CREATE TABLE ta( Z% ^- H' P+ p/ U" I5 \* J9 g
  4.     (
    1 `: f9 s; A: g  L  [- Q6 s" Y
  5.         id int comment '模拟100件活动商品的数量'
    ( ^8 L; j& g, N, u4 x1 ]. W
  6.     );
    ; V7 l& l& I2 u" l" W+ X
  7.     INSERT INTO ta VALUES(100);
    1 t  L/ [' m0 w$ t6 n5 l3 L
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    7 N! b& n. |( r2 E/ D
  9.      */
    3 l6 W; V6 W2 r: h
  10.     & S% r; z5 j6 a
  11.     // 关闭错误报告; s/ d) o9 m. H$ e
  12.      error_reporting(0);
    : P4 Z( ?" V4 V0 A
  13. 0 }7 r5 ?; @! _
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址$ D" A  A& v: s0 ]! M
  15.     $dbuser = 'root';            // mysql用户名; E9 B( A* q. c) N- `
  16.     $dbpass = 'root';          // mysql用户名密码
    7 ~) f5 D5 r  @2 A* g. W" D9 S
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    & A" t  z8 F3 b/ Y# _5 ]
  18.     if(! $conn )) |) w4 O# \( X3 x6 A
  19.     {# k/ Y9 z/ U0 Y
  20.         die('连接失败: ' . mysqli_error($conn));
    8 }2 H% j2 s+ R! v  i
  21.     }2 O  p* J0 J) f4 M4 w: U' k# S+ Z
  22.     // 设置编码,防止中文乱码5 [) h: _# g5 q# ?) `& A. Z
  23.     mysqli_query($conn , "set names utf8");, K2 u2 ^# F' A' O1 u% P  u
  24.     mysqli_select_db( $conn, 'temp' ); ! v& ^4 v9 a6 e) e/ Z: I; Q

  25. $ c5 d4 @5 ^0 B. F
  26.     # mysql 锁 $ {) d" I8 g, ^3 N2 I% S
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    3 F4 p; C1 f: ?) t
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    + o) l, N( e; E" t: p
  29.     $id = mysqli_result($rs, 0, 0); : t/ e  r: ~5 b8 q/ m
  30.     if($id > 0) - X; H) _/ E4 `* k% ^; H+ q5 G
  31.     {
    * x4 Y: N" J+ ]; M
  32.         --$id; ! d. h# O2 j, `1 w6 z0 ~
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); ( z8 I% n9 g) ^" n9 m
  34.     } " g$ X+ I$ _2 j/ `: B2 f( X
  35. ) C! P3 R& J6 H  P" \5 C# j$ u6 d6 b5 V
  36.     # mysql 解锁
    2 N& X6 _' d: t6 R/ Q6 f. ?$ R( x9 M
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    + }! b5 i, Q. x
  38.     //查询解锁后的id值
    $ H1 ^' ]* O' F$ G  M2 L! c  I* U
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    1 H6 n, U/ y1 R, ]) X
  40.     // while($row = mysqli_fetch_assoc($res))
    " ~1 O' Q* P% x1 a9 _0 a2 H) a; r  o
  41.     // {$ C, f1 D% i  Y
  42.     //     $id = $row['id'];
    7 F& |. Q/ f2 I# `' ?) g+ `* j
  43.     // }
    3 f" K  |5 x- P: J
  44.     // echo $id;
复制代码
6 R- t# A9 p; A0 e* `& y5 A
2 A8 ]* j3 T6 M5 E# |
% ~6 J' x6 P/ v$ a+ J0 W; b! T
PHP文件锁示例:
  1. /*
    / u6 F' T8 M- [+ D1 i  R
  2.     模拟秒杀活动-- 商品100件% a: K5 B+ ?& q4 _* g4 v' H1 K1 p" p
  3.     CREATE TABLE ta
    * Q7 f8 \5 d8 P% X( K1 A
  4.     (+ @6 _; m6 w: @. V* d$ i! ]
  5.         id int comment '模拟100件活动商品的数量'
    3 q0 s0 y) R" W
  6.     );
    ; N1 h$ i4 ^0 H: p1 ?; v( c
  7.     INSERT INTO ta VALUES(100);
    * ^0 m: d' R# P  W3 ^$ Q, n1 D
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    # m1 e5 p/ _1 y
  9.      */
    ( b/ |6 Y9 ^: C6 n8 {5 ?% G
  10.     3 [) N( X+ u0 \2 R5 R8 ]
  11.     // 关闭错误报告8 y' p' u" @( }) t
  12.      error_reporting(0); / P* a& L( n) d0 v# b. k

  13. ! k& }; V* G! r7 i4 s9 G3 w
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    6 a) r+ }6 ^9 h
  15.     $dbuser = 'root';            // mysql用户名
    & l& Y- T$ O/ D* @& a! t7 d
  16.     $dbpass = 'root';          // mysql用户名密码
    5 x3 w) x! g  Z* V/ q& S
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    0 l) m; }. J/ `3 G! P" y( V0 f
  18.     if(! $conn )  d) [- s4 ?: u) z3 T: h
  19.     {/ z. ~6 M8 B4 y7 U! m& O4 m- M, c
  20.         die('连接失败: ' . mysqli_error($conn));2 g! C( R, S& k
  21.     }
    # ^/ l; D" T/ L; a% A* S* g
  22.     // 设置编码,防止中文乱码# G3 M" J9 _2 \# O+ G
  23.     mysqli_query($conn , "set names utf8");
    6 F! o7 h2 I" G+ B4 W7 `& z$ U
  24.     mysqli_select_db( $conn, 'temp' );
    " K( h& Z) {) _1 v; ^0 a

  25. 2 }4 m2 d( ]! o- v
  26.     # php中的文件锁 ; G$ L& r+ I: Q* `2 y' @+ C. S
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 ) C4 o3 X3 \6 X  L) ]
  28.     flock($fp, LOCK_EX);// 排他锁
    # n0 j: ?. [5 s! r; b; J( ?, b

  29. 2 H1 [0 o9 U2 W: b, u
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 1 }3 V9 X6 `6 l/ i
  31.     while($row = mysqli_fetch_assoc($retval))
    / _3 c& B! }% T3 [3 T
  32.     {
    5 c3 t9 m2 E2 |& J) M. n$ ~
  33.         $id =  $row['id'];
    0 a' q$ k2 k8 x& i) z7 i9 o4 D& D7 H
  34.     }+ P' T4 H9 ?$ P2 |% k0 I% j8 V
  35.     4 D" }8 N, \" l: a- |& b* f9 J
  36.     if($id > 0) 8 j% s( x! l6 t) v! p7 F* q' a
  37.     {
      W2 X0 S. p+ x
  38.         --$id; * \$ @2 l/ C8 [: A) G
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    $ \$ Z& E( B0 h$ b1 m' e1 @0 u
  40.     } 0 I% e' N) [: Y5 E3 M
  41.     # php的文件锁,释放锁
    8 u3 c, k2 E3 k' Q* L8 |  K( V
  42.     flock($fp, LOCK_UN);
    6 l% K/ e6 Z7 K( a& _
  43.     fclose($fp);
    4 F. }& l7 p6 |9 X4 @5 F) W0 b

  44. & G, o+ y$ u* [/ B! g% ]; a8 d
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');, h; _/ s3 U6 p
  46.     // while($row = mysqli_fetch_assoc($res))2 E) j2 o# G) X1 u/ O) P$ z
  47.     // {
    . z& _8 @! y1 h7 a
  48.     //     $id = $row['id'];3 r, T7 J4 ~( O6 J" N' b
  49.     // }7 y! q( R3 f/ J: Q0 e' ~2 S$ G7 C
  50.     // echo $id;
复制代码

7 [% G$ ]9 S) B# b* @$ `0 G
/ F& x. X% h" l  k
抢券活动实例:
  1. public function envelopeSnatching(){
      n4 D3 U/ ~  |0 Q
  2.         $lingqu = $_POST['type'];- A; N8 e& z9 Q# E( t5 D
  3.         $uid=session('u_id');//用户id, u" j5 H1 C7 v$ h9 q9 |) S" Q
  4.         if(!$uid){
    7 e) E: o6 n7 F0 M
  5.             $data['msg']='您没登录,请先登录!';
    - W# z: g1 g2 z
  6.         }else if(date('Y-m-d') != '2017-12-12'){* N3 e1 i% t- R# u4 R7 v$ e. R
  7.             $data['msg']='不在活动时间内!';
    ! d' Y" A) B7 o2 ~4 @
  8.         }else{
    & K- }, Z& D. \4 k) v
  9.             $hours=date('H');//当前小时数
    8 c) V; C4 @" ~
  10.             if($hours > '09' || $hours > '17'){  J3 m' P( Q1 W4 e( e

  11. # Y7 w5 ~, B; `  j
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的- @6 v) g( ^' W* Z6 U( G  ~
  13.                     if($lingqu == 1){
    : _+ p7 S9 r; A% d
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过: F7 ~) J1 y# B( B# P
  15.                         if($hours > '09'){1 [- l- c" @: I* j" _" ^
  16.                             $num=mt_rand(25,28);//优惠券金额9 \( R. t* q. {5 ]; N- }+ [1 P
  17.                             $id=1;; S9 Z3 ?  G6 s3 Y* L
  18.                         }' f. X0 k5 g8 Q( _% w
  19.                     }else if($lingqu == 2){
    + e7 P, k* A* w* W# p+ A
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();" ~5 N& F" `$ I" T7 u% @
  21.                         if($hours > '17'){4 l3 t; x2 \# ?9 W4 r, I$ z. X  I
  22.                             $num=mt_rand(50,55);//优惠券金额/ G0 Z: {4 c3 G' }& O
  23.                             $id=2;5 I, G2 v# k7 m$ R! M
  24.                         }. e- ^8 `9 N+ i
  25.                     }
    5 O3 O' D. }6 B+ Z, l
  26.                     if(!$id){, Z9 ?% a$ T" h! n. h; O3 [
  27.                         $data['msg']='时间还没到,晚点再来吧。';( {* R; o3 \* J0 _+ l: i
  28.                     }else{
    , ]. S- \7 V5 g
  29.                         if($is_lingqu){
    " i3 ~9 v7 k4 K; c8 t' s
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';+ L# q0 U& J+ F1 {; [0 C
  31.                         }else{
    ; n/ y) @& `, _
  32.                             //锁表8 t& Q5 I% F- O6 f8 u
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    7 z% y0 ^4 ^9 a; ?) w8 @6 e% c% p
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();8 O, N1 [. E0 P# q9 E7 K, N2 Q
  35.                             if($active > 0){
    8 `- D7 ?3 R9 F9 l$ T1 a( E( d- r# g' r
  36.                                 //开启事务
    * Z6 u  G/ _2 O* o3 z+ e" Z
  37.                                 M()->execute('start transaction');
    ' f- _9 E6 W! g" l
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    1 R& [( P* f  Y3 u2 ]2 }2 s6 J
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));0 d! E& e4 ~  [& v5 D
  40.                                 $members_preferential    =    M('members_preferential');
    9 K5 S- b* q) F/ @' L4 U
  41.                                 //对应投资金额,! J, |6 l. H# `0 H4 Z7 e
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));0 l5 d) G& n: ^' ?  t" `
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    3 }6 I: P. P  t- u% r( l" j7 `' e
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    ' y4 v7 k% y& Y# {0 \. L
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券  q0 Z2 B, ^: F8 s
  46.                                 if($save && $add && $add2){
    2 {5 u6 L! v& C  {2 ^
  47.                                     //事务提交8 O) M5 ~# U- z3 b% D& I
  48.                                     M()->execute('commit');+ j: `0 Y5 B  g8 \
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    ( p1 X3 ~4 L( ~4 Y! o$ H# t  N
  50.                                 }else{
    7 }  ?% J/ X! @
  51.                                     //回滚) u& ]: w. r; E5 X0 V3 w$ P
  52.                                     M()->execute('rollback');0 s4 a% `2 g# e) y9 p0 v! m
  53.                                     $data['msg']='未知错误!';8 ~& m6 `2 E) e: v* a  M6 `
  54.                                 }
    ' c1 V& w; g0 C$ W: g
  55.                             }else{5 M  m! d; m9 Y8 y" ^7 A0 p. s, ?( p" R
  56.                                 $data['msg']='红包已领完,你来晚了!';
    5 }3 I0 h, Z1 N/ f* Q: U: a# d
  57.                             }  u. T  @5 H8 u
  58.                             M()->execute('UNLOCK TABLES');
    # n2 `! D* r0 {5 A! N2 R
  59.                         }
    6 w. |1 p5 h, R, b
  60.                     }
    5 K' W) m' x4 U4 u; k+ o) y
  61.                 }else{; y" C" {$ x: P- f
  62.                     $data['msg']='非法操作!';
    ' Z7 E# n% S% C
  63.                 }( ]5 x- f+ V8 Y- {% N8 u" ~
  64.             }else{1 B+ g# W' i9 w2 X- t) c
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    " O( o6 |! `, F# R
  66.             }& r7 _) s6 T6 t) E
  67.         }
    % u: H. V) h) [9 T( ~/ B. Q3 P; s# h
  68.         exit(json_encode($data));7 W. P& v( j2 Q! j. }! K7 X- o
  69.     }
复制代码

$ |4 A5 V5 I) Z; k5 m
; d9 y( v$ Y- w9 k( F/ d
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 00:15 , Processed in 0.071525 second(s), 19 queries .

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