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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9335|回复: 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://请求的脚本
复制代码
9 M$ j7 H# K  d1 Z
Mysql中的锁语法:" G# n; k0 F) g/ [! {
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
: M7 g7 t& v1 l; p1 A3 c$ B6 NUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表# f: Y% m* X1 Y+ a3 p
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
1 }* B+ ~, h! T% W/ k注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
4 [. E" g1 |5 \1 N* ~文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。, R/ q( E9 O2 V! @$ d: F
测试时,有个文件就行,叫什么名无所谓
总结:
) m  q% z+ z. `项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:- e0 N( G# d. @4 M  v( i7 ^/ ]
1. 高并发下单时,减库存量时要加锁
! J! A$ c4 I* U3 M2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*- }/ t" w' s+ k' D, v" U( O2 }
  2.     模拟秒杀活动-- 商品100件9 E' D' o7 N6 j' Q# L; Q
  3.     CREATE TABLE ta
    - ]  U& @9 r5 f2 ^6 ~* X  o
  4.     (* s* P+ a% b& p9 ?5 _$ X
  5.         id int comment '模拟100件活动商品的数量': i8 m$ s( [3 y/ N7 L1 P9 M& X2 a- B
  6.     );
    $ O5 }. c$ r1 k# i8 ^$ K
  7.     INSERT INTO ta VALUES(100);
    4 L8 i' s& A3 h
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件5 U# p( O# J8 C( R: r6 ~
  9.      */
    . t! S- W8 z( S5 A' w) H4 C6 `
  10.    
    * N" T3 b0 d6 ]  V" R9 Q
  11.     // 关闭错误报告
    : N$ w# f: S  g/ R6 C) x
  12.      error_reporting(0);
    : A- x6 L$ B* M
  13. ) P( a% q% t6 {" t! s
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址0 k7 j5 z! F) _- O. D- X& o
  15.     $dbuser = 'root';            // mysql用户名0 j" _  v9 Y' o: c1 ^( \3 @
  16.     $dbpass = 'root';          // mysql用户名密码
    6 f2 {! e8 n4 O' b' a0 L
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);4 ~$ E& F+ i* p+ Y5 c
  18.     if(! $conn )
    " V. d7 H! y: H, ^% L
  19.     {
    4 ?% d4 ^+ b" x$ ^" I. I4 P! R" F
  20.         die('连接失败: ' . mysqli_error($conn));& O7 u3 g/ u: m5 @' G4 E- |/ @6 m
  21.     }$ `9 [) @* U, E8 f
  22.     // 设置编码,防止中文乱码/ s" {5 P9 B" |# s+ w
  23.     mysqli_query($conn , "set names utf8");5 v+ F' p; V( W2 F
  24.     mysqli_select_db( $conn, 'temp' ); & `" J# q6 ?) L/ ~3 \9 y9 D/ {0 X

  25. * ^4 @8 U: ]7 f$ _- Y! ^. F
  26.     # mysql 锁
    # o/ R6 k; |8 b" [0 g
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这   y; v" d1 b/ ~1 X0 V8 [
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    ( ^3 \, ], R& d( B- `6 `6 ~; `; ^4 M1 W
  29.     $id = mysqli_result($rs, 0, 0);
    # D1 d1 W9 B2 ~
  30.     if($id > 0)
    : q" `9 Q3 o* ]) K
  31.     {
    ! O- J" K. }/ ~' c3 G$ V' T) A+ \
  32.         --$id;
    5 Z5 w) h/ e+ s) J
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    $ |0 _$ h1 s7 F9 {; d
  34.     }
    3 P% S7 x0 p4 w" _

  35. 7 f/ x! a* }+ v( P) D! |
  36.     # mysql 解锁 + t; H; G, }8 J, n6 l0 ]7 M
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    # d) a0 {( h, X% \
  38.     //查询解锁后的id值
    ; e) G, X, W! v6 l# Y
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    7 t: N  v; v' t! ]- e6 z% n5 D
  40.     // while($row = mysqli_fetch_assoc($res))
    7 b: x: \9 X0 h, T
  41.     // {, J* Z  T" K4 P' t
  42.     //     $id = $row['id'];2 C( R, \* i4 ?0 @6 R4 r: h1 Y
  43.     // }+ g: C( l; S( l# `; {1 l3 G
  44.     // echo $id;
复制代码
* r8 ?) [& U4 \2 c

% k( L+ {& ?# g$ m. q+ {* n. E( v
- n4 K6 p/ N, ^( d5 _% n: E
PHP文件锁示例:
  1. /*
    7 p) s4 h, u; e7 F
  2.     模拟秒杀活动-- 商品100件
    1 H" V6 ?1 k6 ?# ]1 E! x6 `
  3.     CREATE TABLE ta
    - `& ~$ m: u, @' n7 l$ \" s$ h
  4.     (
    7 w: U, r9 K2 |- [' [; R
  5.         id int comment '模拟100件活动商品的数量'0 j1 n. c2 w7 K
  6.     );
    " P& J0 p3 W# C+ C' S, l, h
  7.     INSERT INTO ta VALUES(100);
    / o( G& r' p6 Z. W7 U
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
      m/ C9 f$ T3 O3 Q4 R3 S
  9.      */
    6 {; u& l: c- t- M! K1 E% V- d
  10.    
    4 h; K1 O. R7 _9 Z' [* [
  11.     // 关闭错误报告
    & {% V9 n7 A- U+ `, N* R, |& B
  12.      error_reporting(0); 9 _4 X; x$ U8 |- \( _

  13. 2 w( }" I# j. Q
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ) O7 @  s% \% x' B2 s2 R! a9 W' P
  15.     $dbuser = 'root';            // mysql用户名7 {( L, [. r0 c  f8 F% Z' J# n
  16.     $dbpass = 'root';          // mysql用户名密码' Q; N: G* q$ [4 Q% U
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);: D0 r9 |! a( Z! k/ S
  18.     if(! $conn )7 |4 m9 W- x& m$ |, _; I
  19.     {% d. W3 L8 J" m5 J8 V
  20.         die('连接失败: ' . mysqli_error($conn));
    6 k, j$ d# @3 k
  21.     }$ h1 K, n/ L: h0 L0 e
  22.     // 设置编码,防止中文乱码* O- n/ a$ A( V; y* o
  23.     mysqli_query($conn , "set names utf8");
    / C% D' `/ g" g* {* V- s9 N
  24.     mysqli_select_db( $conn, 'temp' ); ' A( M$ ?) f; _" c

  25. 0 X" i, Z8 {8 R1 u- @/ S% Z
  26.     # php中的文件锁 $ `! Z$ H+ o9 Y" [. d7 p
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    5 x9 z4 V( z5 Y6 `9 A
  28.     flock($fp, LOCK_EX);// 排他锁 ( j# n2 y$ U4 ^6 a4 ]& W# r: k: g, M

  29. 5 ]$ S* c( W% {; V. z9 [# P
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    3 ^% `: Q& j- q3 q$ P7 t( b) z
  31.     while($row = mysqli_fetch_assoc($retval))/ }6 K& p) {4 }9 o+ g
  32.     {/ B9 X% f$ M4 \4 H5 A
  33.         $id =  $row['id'];
    4 r2 i+ `, w" y8 Q  i. e: j( y
  34.     }+ n- q, {6 d' b! H2 }, w3 u2 O; T! O
  35.     * u9 R! O  I3 {: U7 B2 L+ ^" `
  36.     if($id > 0) 4 u( |4 w  h6 k# w% e; l7 F* a
  37.     {
    ' }/ ^; w1 ?3 W# S, _, F) i" z  E
  38.         --$id; * c/ J& X# `" Q" r
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); , N3 u* ~9 a$ p( K& o2 g
  40.     }
      j9 i. [( ]+ b, {4 R* f
  41.     # php的文件锁,释放锁
      [% z9 M& j; L+ G) e
  42.     flock($fp, LOCK_UN); 4 H. {# q6 T2 h" F( X# M, Y
  43.     fclose($fp);- N8 V4 J- E! v, M
  44. 4 f5 l  _" @  `* ]6 }
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ; K% _. H9 @# s' h9 M) M* @, p! j
  46.     // while($row = mysqli_fetch_assoc($res))
      {* R% I" F5 k2 L
  47.     // {
    + Z, ^# j; e9 ~7 w: L
  48.     //     $id = $row['id'];" }; R0 F9 q* q; H3 z! N6 B( X
  49.     // }
    4 i' |' `* }3 ]; n
  50.     // echo $id;
复制代码
# W) E. @! d. w3 H- h4 M+ |
) I( g" V: j4 ^  Y
抢券活动实例:
  1. public function envelopeSnatching(){
    ; A+ W4 v; y. x  ?$ h$ L
  2.         $lingqu = $_POST['type'];$ \- E* M8 `4 z
  3.         $uid=session('u_id');//用户id# T, b! y, a) U  Q) b1 o) {
  4.         if(!$uid){  P; P- }5 W, S( w
  5.             $data['msg']='您没登录,请先登录!';
    ) j8 K2 r/ o$ c
  6.         }else if(date('Y-m-d') != '2017-12-12'){& ~3 b& U1 S: M  W8 o. ~6 Y
  7.             $data['msg']='不在活动时间内!';+ [  D# H$ |9 w6 n4 a& ^9 l
  8.         }else{! F# Y5 W, S4 n, ?" P
  9.             $hours=date('H');//当前小时数, W3 e% k* y! R; D
  10.             if($hours > '09' || $hours > '17'){( I0 w+ P  E: i) n

  11. * E" U( g9 t5 E6 p" Z- H9 w# {
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    6 j  C9 s% O' e9 K9 `
  13.                     if($lingqu == 1){9 x' O2 I! K2 x" R! C
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    . I- q8 l, F5 T1 c$ C/ {% w
  15.                         if($hours > '09'){
    3 A& Z0 w% o" W7 ]+ `
  16.                             $num=mt_rand(25,28);//优惠券金额
    8 ]  O2 S' y% |: ^. e0 s4 X9 b( h
  17.                             $id=1;
    2 l# s9 v: G( W0 m' Z3 @# I
  18.                         }7 ^8 F0 G0 @1 Z$ t
  19.                     }else if($lingqu == 2){
    4 c% t8 O. f! U! b$ D
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();( S1 q4 ]( j+ Q; g8 u3 a8 j
  21.                         if($hours > '17'){$ A% X+ ?- g0 @- F8 n' y5 O1 k
  22.                             $num=mt_rand(50,55);//优惠券金额6 F$ m- `; ^! O/ }2 q
  23.                             $id=2;& U3 P2 w) ]0 w9 @1 w% ~
  24.                         }" X9 G6 N5 O2 v0 k3 z6 V
  25.                     }. m/ _1 k: G# h" B* G
  26.                     if(!$id){
    7 n3 T2 ?" p; [* N
  27.                         $data['msg']='时间还没到,晚点再来吧。';& u' m+ S: v* i6 A- N
  28.                     }else{
    / N* g- y$ ^5 S) ]
  29.                         if($is_lingqu){& ^" L' b' P' p( a- i% N3 U
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';& j6 z  z8 v# b; f1 m
  31.                         }else{! e2 E  j4 z3 T( [0 z9 A
  32.                             //锁表( {9 ]* [5 _7 V, B. U$ H9 s! Y1 d
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');) l4 u4 j" F. _. f' T+ u+ h" k2 C
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();  ^% Y$ z# I2 c  q8 f
  35.                             if($active > 0){
    * b4 \: T* Z/ I% L: S$ P
  36.                                 //开启事务
    ) O* g1 K8 b( Y% h5 t0 v
  37.                                 M()->execute('start transaction');
    8 W+ d1 _' I7 Z5 M, t0 w
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    & ?0 k9 }9 b  A9 r1 b' v; a
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
      T5 p1 Z+ J5 k4 }
  40.                                 $members_preferential    =    M('members_preferential');9 Q' v' X$ E# N0 U
  41.                                 //对应投资金额,
    1 X0 x0 R* e) N8 X1 s* k
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));) x! k* }1 }& M7 U. d+ M
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');; S" w, r2 Y. O; T5 |. A  R
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    9 i2 I( l. S3 R2 M: K5 J
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券$ P' z. b% ?" r4 H; {/ j
  46.                                 if($save && $add && $add2){
    7 D+ o, ^6 A; g+ i, W! E
  47.                                     //事务提交
    2 g. o  y, q$ a' G0 D5 d5 t
  48.                                     M()->execute('commit');
    " f1 H) \" [3 h  l( I# g
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';  b( I4 K8 A9 x; H: ?& Q& w
  50.                                 }else{  K0 C# q) `- l% V! j
  51.                                     //回滚2 P9 W. ]  o5 i1 g% R9 n8 n9 z
  52.                                     M()->execute('rollback');
    ( l: R: {+ b7 H, }, o; S- j
  53.                                     $data['msg']='未知错误!';2 j, g* o& d9 \
  54.                                 }
    6 u3 \2 n- I; x1 \- r8 E9 q2 A
  55.                             }else{2 u2 I! G" y0 a+ O& j- J* u: S# P
  56.                                 $data['msg']='红包已领完,你来晚了!';- ^% v8 n8 U6 f9 Z: R; }
  57.                             }; p" _* P6 ^' k) q/ R1 ^$ P3 z
  58.                             M()->execute('UNLOCK TABLES');
    4 R* c( C% _( m. g6 {1 @/ v
  59.                         }
    - K( f1 E7 ?, L
  60.                     }
    : N9 k, W; j, N' K( y2 j# ]& p: P
  61.                 }else{
    , M) Z; p6 ~7 f
  62.                     $data['msg']='非法操作!';1 h1 l* D* A5 e' c! U# `
  63.                 }! Q& H, Q# E7 Y: R6 f+ v! X
  64.             }else{
    $ c2 v0 l0 L9 e% u( x* o
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    - }+ N% D+ _1 U- |
  66.             }
    , v4 X( a% I  [3 n. u! B
  67.         }
    , H; {* l! c3 J/ I
  68.         exit(json_encode($data));
    ) F  J5 h3 r: i! j1 [0 _$ n& y' m6 ]% f
  69.     }
复制代码

9 R! I1 A+ a5 Q$ |$ y
5 P, X( M! }+ N8 F
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 11:35 , Processed in 0.052641 second(s), 20 queries .

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