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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

' f+ T& ^$ U$ S. q3 u
Mysql中的锁语法:/ Q% g2 E0 O$ k9 r/ |$ [# B8 s- H
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
" q+ l" O! o* |1 E' NUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表) v# F# y# @" f+ q% V3 [8 @2 t
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞8 I- D7 ]; y. H* `2 o
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :+ M+ d7 F8 [2 Q) ]# Q
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。8 @# m0 ?* q$ n' Q  |* T% Y
测试时,有个文件就行,叫什么名无所谓
总结:# Y; A. T! P. i+ J! N6 i* v
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:2 v5 @) g" L8 z9 ^' I0 R( i
1. 高并发下单时,减库存量时要加锁
, A3 Z/ [* n4 |1 z2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    3 R6 l7 r3 g$ v
  2.     模拟秒杀活动-- 商品100件
    + e0 u- x' `. v+ p* ?  n  x
  3.     CREATE TABLE ta
    6 K, t1 d2 m0 m+ w  p1 E" O
  4.     (2 c8 [$ |8 B3 n
  5.         id int comment '模拟100件活动商品的数量'! y/ f' ^1 V( z! s! e
  6.     );9 H# }4 \, c2 w2 [
  7.     INSERT INTO ta VALUES(100);
    $ Y8 Y( L( C9 j4 M4 R
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    4 u6 ?# X- z- d6 y0 B5 c
  9.      */
    5 J* c- ]2 ?' Z
  10.    
    ' {4 j& e2 l) N& o% ?4 M& {! N
  11.     // 关闭错误报告7 Q( l6 k# n' {0 B$ M
  12.      error_reporting(0);   T/ O& g* c2 Q
  13. . D* m. K3 f& z1 D. |4 U
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    * v! y* u/ F8 v1 Y& e
  15.     $dbuser = 'root';            // mysql用户名  @& O( _3 M$ ?+ U2 Z+ @' n
  16.     $dbpass = 'root';          // mysql用户名密码
    / K: s* }/ v( q8 J) t
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);+ x/ k5 a3 l7 O7 i# a2 n1 x
  18.     if(! $conn ), u4 h6 O! j% `' s
  19.     {
    & K6 k% L) a' I  b4 Z) o
  20.         die('连接失败: ' . mysqli_error($conn));
    . P' C9 i' f; C, a* E1 B4 p  w7 O4 U8 t
  21.     }1 Z; z. N" W2 z8 Z( V0 Q5 i- e* z2 c
  22.     // 设置编码,防止中文乱码
    5 x* f! F) p, w
  23.     mysqli_query($conn , "set names utf8");) b  }1 w7 @! v2 u- y4 u
  24.     mysqli_select_db( $conn, 'temp' ); + M$ v. a2 G; }7 W
  25. 1 v; `9 }1 ]0 K2 s% b! `1 {
  26.     # mysql 锁
      x( y  Y! M6 [6 z$ W
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    : F: W+ V5 Y9 v, ]5 R  ^
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 9 x! ^% N* q) p! K0 W
  29.     $id = mysqli_result($rs, 0, 0);
    1 i5 h% F2 y! K0 s" m: {9 K4 u
  30.     if($id > 0)
    7 U% V( e6 {1 s0 n9 P( {
  31.     { ) d) d; [0 `+ b1 O. c8 J! x6 n/ b
  32.         --$id;
    & l% j- H' t! S, h
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    - G. T9 B( V$ T; a% N/ m4 u
  34.     } $ c+ k3 Q$ y6 |, w( ]1 J' ~% I

  35. % h& ^' g$ ]6 l4 o7 G
  36.     # mysql 解锁 1 Q1 o; i$ ?: a! k8 [0 Q/ e
  37.     mysqli_query($conn , 'UNLOCK TABLES');* o9 }" v2 M1 E: A6 E
  38.     //查询解锁后的id值2 o# Y+ {. u, I# W7 S+ o. v  p
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    : Y3 g, A% d( a1 `; n' ?7 C1 ]: {' e8 Z
  40.     // while($row = mysqli_fetch_assoc($res))
    ' F3 g- S/ ]: P7 ^7 P0 O$ p0 Y' r
  41.     // {
    , W* R# x  y$ Q1 ~8 H1 N
  42.     //     $id = $row['id'];
    ) E- k3 o4 U; @
  43.     // }+ z: Z. T+ T* J! c  v
  44.     // echo $id;
复制代码

5 A5 H0 {* l: x8 E8 Y5 E
  u7 ~3 ?. R+ ]

) L6 J! X: X9 S& z+ Z/ j/ F' q+ K
PHP文件锁示例:
  1. /*
    9 e: S/ c7 y/ ]+ R% t" h! ?
  2.     模拟秒杀活动-- 商品100件6 w7 b9 Z" G; }) \2 C  Z
  3.     CREATE TABLE ta- d) ]8 R8 ]9 e2 Q2 e5 F, f
  4.     (6 T1 E; L4 B# z1 |# a) u, C
  5.         id int comment '模拟100件活动商品的数量'7 k, w: z" F$ x# s  z3 M0 w
  6.     );
    5 Y8 V% C8 B6 ~# W% S7 t# p& L: m
  7.     INSERT INTO ta VALUES(100);
    9 a7 [1 V" q- G- |& c
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件3 B) p" X$ a6 X' d4 ^, x' [
  9.      */
    % N& P, o5 n2 ?6 ^- a' X
  10.    
    1 u- c' A5 }5 g2 u
  11.     // 关闭错误报告* b7 `( e7 t: j
  12.      error_reporting(0);
    4 g% D- T6 B% R) ^" P

  13. % _! A5 Q+ A! ?, D
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址, e+ Q1 N, M7 E
  15.     $dbuser = 'root';            // mysql用户名7 T. I7 |4 y/ ?# H
  16.     $dbpass = 'root';          // mysql用户名密码
    . N2 h" B. g: G/ F
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);$ q3 U8 }5 P/ L/ Z- W" j
  18.     if(! $conn )1 v0 J. U; W9 }" K
  19.     {" i4 x5 ?" R* L4 f# H# [
  20.         die('连接失败: ' . mysqli_error($conn));: P' \3 S' F5 v" k
  21.     }
    4 a" j  t( |5 s3 g9 U2 C- s
  22.     // 设置编码,防止中文乱码
    2 k9 ^; P/ G/ u/ j' m1 c7 j# ~  a
  23.     mysqli_query($conn , "set names utf8");3 R' ?- [: t1 D9 }6 q
  24.     mysqli_select_db( $conn, 'temp' ); ! x# M0 P3 j/ k) m4 t
  25. & g2 M2 E( V2 Y# [) {  H6 Y
  26.     # php中的文件锁 + m7 h0 K8 j; Q
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    : m0 j8 t! T. ]& F8 n1 t7 i
  28.     flock($fp, LOCK_EX);// 排他锁 2 N  V$ |0 |+ z; {
  29. $ g& s2 O5 x/ Y/ O0 Q2 t+ q
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    , H" B1 s) J! i4 z+ o, u  a  k
  31.     while($row = mysqli_fetch_assoc($retval))' {( U5 ?% B, U7 \
  32.     {
    3 @+ z( T( u$ j4 I, r: ~) v8 D
  33.         $id =  $row['id'];7 u7 a* I: _" h' p
  34.     }
    - T- I0 @  ^" O/ f
  35.     6 i! S4 s9 z; D) F8 J
  36.     if($id > 0) # I3 z- k- b3 O$ \  t
  37.     { : }7 P4 j6 f7 G2 E* N
  38.         --$id;
      ^  \0 C  h: v6 w8 M. r" H' q& C
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    & C7 a: j6 [' H
  40.     } $ E  ~5 i3 u1 z  t6 |4 x& U& I# e* m
  41.     # php的文件锁,释放锁 9 q; K- |4 U6 E) ^: F
  42.     flock($fp, LOCK_UN);
    + R+ J; _/ [, T$ f* U, u
  43.     fclose($fp);
    2 H7 i: @$ [1 t! q0 o* s5 `# Q
  44. 5 c& D4 t' \; y' r% y- Z
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    % ?% Z% S5 O$ |$ \
  46.     // while($row = mysqli_fetch_assoc($res))' v; m$ p. c; l9 [; `( z" N8 F
  47.     // {- c$ b' e8 X" J- W( T
  48.     //     $id = $row['id'];
    / ]4 D% q4 g; n. a" J
  49.     // }( X3 [) G4 d, D* d0 W8 K
  50.     // echo $id;
复制代码
* R( j, ?% ?* n' f3 `/ M

! a" ^/ {' u4 W5 r5 k) Z
抢券活动实例:
  1. public function envelopeSnatching(){; v- r1 ]0 k; b9 C: s3 L- ?
  2.         $lingqu = $_POST['type'];! b/ y& x) U( @3 y
  3.         $uid=session('u_id');//用户id' w6 f2 {1 o; _* w2 @
  4.         if(!$uid){8 J4 F- y& o' @( _5 D3 D
  5.             $data['msg']='您没登录,请先登录!';
    6 o7 X+ r8 m! W3 r2 {
  6.         }else if(date('Y-m-d') != '2017-12-12'){8 ^$ T5 E% J/ c" \
  7.             $data['msg']='不在活动时间内!';' s0 t+ i- k. y2 l
  8.         }else{9 M! m: ?7 I; Z, l5 u0 Q
  9.             $hours=date('H');//当前小时数0 b) D5 U  |& _9 F7 r+ o
  10.             if($hours > '09' || $hours > '17'){
    , t2 [$ `! q" R( Q+ J, P6 p  a

  11. : ~0 D( |6 J' `5 J) |, D, I
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    " g0 W$ M! [' E. K. D8 ]% P
  13.                     if($lingqu == 1){) e! a9 ~1 q$ F: {  f- ]& `
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    5 d# H+ c# c  o& P2 f
  15.                         if($hours > '09'){% D0 @1 `, f% k+ {( F6 a# y( \
  16.                             $num=mt_rand(25,28);//优惠券金额
    ) p) h9 P9 V5 A# a$ o" n
  17.                             $id=1;1 F) v1 T1 v4 n# n
  18.                         }- @/ ~- n: ^  s# d0 s. Y
  19.                     }else if($lingqu == 2){
    " @, k. L" G1 H! |- Y" |
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    2 ^  K1 L) x* {
  21.                         if($hours > '17'){0 C6 X* ^& E5 A7 N
  22.                             $num=mt_rand(50,55);//优惠券金额' c# d2 ^7 J3 R. [: f; \
  23.                             $id=2;# ^; l9 I4 }7 H8 F
  24.                         }6 @8 q! _& H$ b4 O6 q5 s0 d5 A
  25.                     }- E  T9 x$ W1 s8 d1 T. s" d
  26.                     if(!$id){; v3 N* j. k, M( ~
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    4 s' C7 Y) r: x7 W: T' l
  28.                     }else{
    - [' s( Q7 h2 e0 k; _1 Y3 c+ N
  29.                         if($is_lingqu){
      i; D' N9 i2 c) u5 N6 x
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    5 A) F% D: P. r( r& V
  31.                         }else{
    ! X* E$ j# C6 X0 P; q8 z$ p- K" v
  32.                             //锁表
    % u5 w8 @: y3 `/ j6 y$ E1 H
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');* m8 K+ `  r' X: {- Y; c
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    * F, N2 B8 s' e
  35.                             if($active > 0){4 I0 `; l& n2 t1 I/ Y8 M
  36.                                 //开启事务
    5 \+ `- J3 ^' i7 T
  37.                                 M()->execute('start transaction');
    9 s& |5 u8 ?1 F9 @1 Q+ }
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));: f+ _8 l5 _2 f0 [, d, \3 B
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));$ C8 |+ a9 K( t2 T
  40.                                 $members_preferential    =    M('members_preferential');8 j% k* |+ |+ d  w( N
  41.                                 //对应投资金额,
    ) c7 N0 h$ m4 w8 R2 j
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    $ _6 d. ~9 C9 ~! G; S+ t
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');4 V8 k0 h+ z+ T* c7 L
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间! _0 k/ s) T5 Q
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    & q% W2 V6 |0 p  T' @  v
  46.                                 if($save && $add && $add2){
    * X7 T$ [; x: N9 }( v$ m
  47.                                     //事务提交1 H# M) d, h3 r+ {
  48.                                     M()->execute('commit');
    ( B. P' @7 t- \
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';! T4 y% x0 h7 a. ~+ p/ Y/ t
  50.                                 }else{
    0 T2 B) r' f3 ^$ S9 F
  51.                                     //回滚" q3 d! Y: E, `# J$ G- U
  52.                                     M()->execute('rollback');
    ) I& Y1 G1 X9 N
  53.                                     $data['msg']='未知错误!';
    + M5 A7 X7 k3 h. r' e. t# k0 ~
  54.                                 }0 f3 z. T* O2 {1 O
  55.                             }else{
    2 s6 j- Y+ e: p- c' \8 A
  56.                                 $data['msg']='红包已领完,你来晚了!';' K; u# L4 o) F7 p7 E
  57.                             }
    # H; k# e+ p4 ]# V( d
  58.                             M()->execute('UNLOCK TABLES');; c" P; m5 q8 L. F* N, {% Y7 K8 k, m. z" i
  59.                         }- ~8 Y3 L$ H7 D+ G! C
  60.                     }
    8 O4 i+ j" L5 ~0 {4 l, s4 G
  61.                 }else{( _! w0 a4 _( K
  62.                     $data['msg']='非法操作!';$ j# e1 ?0 {0 x' r4 C
  63.                 }
    5 ?, U/ @0 V5 H: Q2 D' R4 y
  64.             }else{* x: }( e1 X0 O! c  z! i) `
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    - p6 s# k( A2 |5 D6 F
  66.             }
    6 ?0 D6 l2 K% i7 L8 w- J( [& a
  67.         }
      F: f% [: w: d+ _# H
  68.         exit(json_encode($data));* w5 i& @3 |5 }4 m7 o5 I" m' B% J
  69.     }
复制代码
6 {* c( d: o& E7 Z4 H

! j% _& O. K; {( g+ i5 d& ~
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 16:44 , Processed in 0.056547 second(s), 19 queries .

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