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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

- i' L1 M3 O* t' R8 G- M0 f$ @
Mysql中的锁语法:
# u( H: g5 \' @4 K- pLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】% y6 A6 L$ i$ u: ?3 w/ [3 y2 e* F
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表) `& }. h3 m7 E; W# P. [+ h$ z
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞  u- ^" P, c1 M" S( M5 ~
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
2 d: }/ [1 d, ^; B% {- B6 [- d文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。! M6 ]! [4 N4 D7 S" _$ Z$ z5 w
测试时,有个文件就行,叫什么名无所谓
总结:6 Z) }, |4 }0 F
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:( L. C7 O6 |8 c: M) F& }
1. 高并发下单时,减库存量时要加锁+ a6 g9 p+ q; j
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*3 F# I9 A/ U2 h) T5 Q0 n
  2.     模拟秒杀活动-- 商品100件1 I3 O2 H: ]) H) m* u
  3.     CREATE TABLE ta
    2 x' t3 B8 {* R, y
  4.     (
    " Y: i; \8 ~' W$ s, {0 S
  5.         id int comment '模拟100件活动商品的数量'- d& u$ B  [. N
  6.     );! T6 I' b& X; Y% b  r3 p
  7.     INSERT INTO ta VALUES(100);9 o, O6 X# \1 h/ q( x
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    * _/ ^4 w5 @8 c, N7 p
  9.      */
    0 P2 H$ Z9 p  S
  10.    
    1 D6 p4 Y) c9 _, _& Q* a
  11.     // 关闭错误报告
    7 V! U! L( j4 q) `
  12.      error_reporting(0);
    # m7 a; F! p2 ?) e* b  d2 K

  13. ! h" J' a. h+ [6 n' m
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址) v# @) g, Q3 A3 e
  15.     $dbuser = 'root';            // mysql用户名
    / j3 b2 ~6 J; F& g/ b6 x( H
  16.     $dbpass = 'root';          // mysql用户名密码+ J% u5 R/ z  Q+ I0 G0 j: c/ K
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    # I* i5 ~+ X; `; {/ }; k( m
  18.     if(! $conn )
    % j. L  X* _* h% z3 `, s* C
  19.     {% u! \4 T3 l! _6 V9 m
  20.         die('连接失败: ' . mysqli_error($conn));6 g) j" r8 C6 A, Y5 W8 E: L
  21.     }
    4 R1 ]; X1 i# U7 O& y; H" }, `
  22.     // 设置编码,防止中文乱码( Y# u# E: f" V" b! K& O* e2 G
  23.     mysqli_query($conn , "set names utf8");5 L3 Z& @, l) J4 w
  24.     mysqli_select_db( $conn, 'temp' ); * T# @( `2 `7 W; @' N. a2 Y/ M; x

  25. 9 i5 b$ M- W6 q
  26.     # mysql 锁 $ u& q) O- ~+ [/ W; n
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 2 }( z0 o2 a! T  v1 T: d
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    0 f1 ]# a. R3 v7 D
  29.     $id = mysqli_result($rs, 0, 0);
    5 D# V% M/ }' {  E7 a+ s# ]
  30.     if($id > 0)
    ( |, L+ }" c; R" C! _+ N9 ~
  31.     {
      N, H5 E% @9 P) C5 l
  32.         --$id;
    / d6 J% X7 o7 u
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 5 ~2 S* Q; ?9 P) R1 |& t
  34.     }
    $ L& L' t% h& D& x0 d+ v

  35. ( e; @  T3 @9 {8 a; N- J3 l8 n$ g2 j
  36.     # mysql 解锁
    : o' @) V. ^) e! w. g& K" u: `4 X- t
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    0 _, e; y5 [2 w) d# k" A
  38.     //查询解锁后的id值8 c5 `8 b! Y/ l4 f
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');9 W4 I( A' q& |; w8 |& ?
  40.     // while($row = mysqli_fetch_assoc($res)). o" [8 [$ l- M8 c3 b$ J  w
  41.     // {
    $ S! D0 Z) R" o+ x
  42.     //     $id = $row['id'];6 U( ]2 a' ?9 H9 y: u( E
  43.     // }# l2 u4 }8 M$ k" Y: @$ m
  44.     // echo $id;
复制代码
6 M- x  K5 o% i% ?2 B8 K8 @4 C5 e
5 O& c- O: X4 l) U

! ^! y' ]6 k( M' {2 t: p2 b* B
PHP文件锁示例:
  1. /*
    & y' M# n) R7 V9 W' y8 q; A
  2.     模拟秒杀活动-- 商品100件0 H. d2 f# g& ]  t7 K! O  `! S2 A
  3.     CREATE TABLE ta
    # J0 K& }" f+ j1 U
  4.     (
    " ~. ~8 |, x. l# O
  5.         id int comment '模拟100件活动商品的数量'- k' E, j+ F& I$ U( b7 A
  6.     );
    : S3 D, y) v7 K
  7.     INSERT INTO ta VALUES(100);
    8 `: @. X* Y$ S0 R( a# A$ a, ]0 f$ m
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ' ^  V$ u- {( J- m3 p# b8 G" V
  9.      */
    7 @' X5 ~: J' w; j8 y( I' g8 @5 C
  10.     " ?. C+ ?. S7 j  L4 t5 w
  11.     // 关闭错误报告
    * Q7 |8 f( s4 G" K, o6 G. D
  12.      error_reporting(0); - U: A9 \$ k. K

  13. : l8 B. H# U/ ]9 j. ^. E2 o
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ) B* S0 i: z% v, e3 Q7 E
  15.     $dbuser = 'root';            // mysql用户名/ {/ t. x( |% J- C: M9 P5 B3 e
  16.     $dbpass = 'root';          // mysql用户名密码9 A2 a% O# E3 k, u  B
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    5 O4 Z0 O3 D& u8 h
  18.     if(! $conn )* ~. O" R" a" M; F4 |8 w7 G
  19.     {
    ) e9 x) R" D# o% B
  20.         die('连接失败: ' . mysqli_error($conn));
    # c! }& h8 d# H1 G! O7 T: @5 ?; v
  21.     }9 t9 D! k! [8 h0 Z' l
  22.     // 设置编码,防止中文乱码" Q5 i  {3 m# L( n2 r
  23.     mysqli_query($conn , "set names utf8");
    7 Z2 R8 R! h" N: K* \/ f0 ^
  24.     mysqli_select_db( $conn, 'temp' ); 8 _& x6 e8 @# S
  25. 4 O8 v* r- k0 i7 f) A
  26.     # php中的文件锁 2 I' e9 E) O7 u6 K+ K
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 # ~, P! a* {# v
  28.     flock($fp, LOCK_EX);// 排他锁
    - j, M4 \& p5 F1 [; _5 A

  29. 6 T3 d& A, k& F, W  n  x
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    . Z5 X6 w' f- m6 ~& K2 P4 k0 C0 W
  31.     while($row = mysqli_fetch_assoc($retval))
    3 W4 R6 t, n& b7 v
  32.     {
    $ P* e: \6 u5 y0 r6 i$ A- J
  33.         $id =  $row['id'];
    : g; q# H9 _/ b, [! }1 t* x, M
  34.     }
    3 z+ k7 X5 }+ `
  35.     - Y! d  Q5 X% v) b& E7 T/ n
  36.     if($id > 0) : V( K6 {- p) T
  37.     {
    ! I; a& X; }+ R6 R- y
  38.         --$id; 0 ?8 D( R/ a" Z
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); ( Q/ F4 ^4 |; x& a9 k
  40.     } 8 R! o5 u5 e; y1 t+ _
  41.     # php的文件锁,释放锁
    , F8 j) }3 a  g+ f# f* G5 Z6 b
  42.     flock($fp, LOCK_UN);
    + n) g3 i( d% I: g  |1 ]
  43.     fclose($fp);
    - P# w7 v8 w# @
  44. 0 I! P; v9 Q6 u
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');7 m$ w0 t. [! \. M0 h4 n2 l
  46.     // while($row = mysqli_fetch_assoc($res))
    ) g, l6 c/ g  x
  47.     // {
    9 A. P; p5 i6 T- e" `: x: J
  48.     //     $id = $row['id'];( l& s$ `  N4 C6 p7 ], K
  49.     // }
    0 q( B! y/ I( w% [
  50.     // echo $id;
复制代码
6 I& n9 T: l$ X1 B, O

* X6 W! T4 f1 p6 ]
抢券活动实例:
  1. public function envelopeSnatching(){( y2 B- u+ _" v# H
  2.         $lingqu = $_POST['type'];7 |5 ^$ j' A# b  k
  3.         $uid=session('u_id');//用户id
    6 \: f* d  q; N8 h3 A, w
  4.         if(!$uid){$ R# d- l8 ]! D% I2 y
  5.             $data['msg']='您没登录,请先登录!';
    ; s, _% i4 S* N! h! d# u
  6.         }else if(date('Y-m-d') != '2017-12-12'){) W; ~2 X+ W4 u' c$ s
  7.             $data['msg']='不在活动时间内!';
    1 p# d* p7 w  j; U
  8.         }else{- p( |, G" L. z, C' d
  9.             $hours=date('H');//当前小时数& {! a; }, L9 A/ O7 ?3 q
  10.             if($hours > '09' || $hours > '17'){
    ) e  O8 y4 Y: ]8 x* J
  11. ) c6 ^" N8 ^5 [! x( \$ g
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    ; d7 ^$ a! {9 Q+ F- v  m( [! J
  13.                     if($lingqu == 1){
    4 ^  i0 c: l9 M. b3 v' @
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过* C, f7 g- d' d$ z! [* C
  15.                         if($hours > '09'){
    + K7 e, y" E' I1 [3 h, d4 b
  16.                             $num=mt_rand(25,28);//优惠券金额
    4 h. y! [0 T( f) q
  17.                             $id=1;
    " G2 }3 r! r$ ~0 h; v( m1 X
  18.                         }, h" o) E1 @& Z8 ^  t9 W, e: i
  19.                     }else if($lingqu == 2){
    * D+ W# N6 Z2 c% z! M+ @8 N. ^
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    % }0 t: p8 M5 B2 M0 k/ L
  21.                         if($hours > '17'){( F( V6 s0 g: V  p* u9 M$ F
  22.                             $num=mt_rand(50,55);//优惠券金额
    ! I" y. y! `: P# M5 m
  23.                             $id=2;
    " [$ c$ h: a" }2 ^8 B8 P: J6 {
  24.                         }7 |; i& J, _% K9 e1 `# v
  25.                     }* H7 u  O$ s7 Z- r# r% N6 F4 \
  26.                     if(!$id){
    $ a6 Q& A  z9 i7 C
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    " u0 f' G8 T8 Z6 N: m6 P
  28.                     }else{$ |9 L" o4 H6 J7 R; h
  29.                         if($is_lingqu){
    $ e0 M4 T* S$ b8 G# E0 h
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';0 ]" z5 B7 I0 p8 @" ?
  31.                         }else{
    / f* p8 |) b5 ~) k4 ]
  32.                             //锁表& r5 |- E3 Q! N3 `( x
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');' m) D, S1 O' k) r$ e5 A3 k
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    2 d% Y+ u5 [- {$ n, Q) w
  35.                             if($active > 0){4 F& t( H8 ?! b
  36.                                 //开启事务
      m( m- r) B4 w2 _" r; a' F
  37.                                 M()->execute('start transaction');
    / ^$ q& e/ I* [0 b; v
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));5 \. y; u6 ^& u
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));! W. V, Y' q8 P# R! v* m4 s
  40.                                 $members_preferential    =    M('members_preferential');
    0 z; y8 u* o( y, F
  41.                                 //对应投资金额,0 L/ i4 |, t3 q% V; l# j/ ^
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));4 [$ D1 p3 m, o- }; k/ m
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');  |. q6 h& Z( k+ p! X& k2 F
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    : X2 o2 w3 d. s3 C' [: e" t. D
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券: ]% S6 k5 ~; G$ P% i2 A
  46.                                 if($save && $add && $add2){
    ( A; L( B! t- Z8 F! [
  47.                                     //事务提交
    0 I, I8 U( W1 M. a
  48.                                     M()->execute('commit');4 F) Y& L3 c& ?0 `% G* ]7 z
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';( `* }3 }; g( [$ r, k' q: U
  50.                                 }else{
    ' g0 ~. @, i9 X9 _9 |% a
  51.                                     //回滚
    . U* P5 F) `9 p- {  j! Q
  52.                                     M()->execute('rollback');* e  h  V: \$ t) A5 ?) b
  53.                                     $data['msg']='未知错误!';  ^% k' J% i9 G5 `
  54.                                 }
    % U7 j, e! o  s
  55.                             }else{9 B$ K6 P. E7 W# n6 U
  56.                                 $data['msg']='红包已领完,你来晚了!';
    1 |3 ]8 d8 [* f1 t" J
  57.                             }
    7 ]4 T7 C4 c1 s. m
  58.                             M()->execute('UNLOCK TABLES');
    0 ^- }' e; j9 i6 v3 k$ Q
  59.                         }
    & l, B, ]1 `) ~" K
  60.                     }8 |' D7 q: V9 r1 C
  61.                 }else{
    & q* S# W2 K6 c8 `- H
  62.                     $data['msg']='非法操作!';
    ! O& E  v5 \  V* A/ G
  63.                 }, ^  T7 ^! h9 ]& h/ w/ F
  64.             }else{% R; C! @( e, E' L, y
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    & v) V# r( x. |4 u1 E7 M9 L
  66.             }4 a, P$ }3 c, t5 q% V
  67.         }
    + ^; a" H7 t0 Q+ q8 P, T
  68.         exit(json_encode($data));0 a1 K! {/ h9 Z
  69.     }
复制代码
1 s! z7 Z6 ]1 Z# R0 `" d

. J: K3 h- K3 U3 F7 H" z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-5-2 11:46 , Processed in 0.058200 second(s), 19 queries .

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