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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9874|回复: 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://请求的脚本
复制代码
" ?; G% r+ B$ S' O+ s' z
Mysql中的锁语法:
5 s% d3 z# I* Z, i& oLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
9 z0 V* H. W2 [0 b- t: \UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表; @: s4 ^6 C+ D0 M$ S
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
) U, q& x" v. N2 _" v' b注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
* O# ?6 x( _1 x* [7 j3 g5 j文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
9 S9 n+ J: u, ?测试时,有个文件就行,叫什么名无所谓
总结:
$ r* g" w# i' j7 J% k  s# [项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:9 }& |- z; L* p  E4 s
1. 高并发下单时,减库存量时要加锁, W2 q+ `  J6 C& c8 b8 H
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*2 _; n! u% m: ^: K7 }7 Y4 O
  2.     模拟秒杀活动-- 商品100件
    3 S4 Q$ Z4 C6 E& Z' C
  3.     CREATE TABLE ta, V+ t6 H% y4 c& ^- a. R8 `/ M
  4.     (6 Q0 m' @2 w4 r! Y
  5.         id int comment '模拟100件活动商品的数量'
    2 P+ H4 i1 u9 _5 R8 q
  6.     );( Y+ ?4 h' E5 X4 i
  7.     INSERT INTO ta VALUES(100);5 R8 ~" y# t; j
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件& H* h% G9 i4 @
  9.      */ 5 h' C$ F, s3 X1 J: ]
  10.    
    ! v/ [+ v1 q" @; V
  11.     // 关闭错误报告
    0 B/ Y1 W& X; e' g+ \/ N0 B; p! I6 V8 E
  12.      error_reporting(0); $ U# W  X( T+ R, T- q7 [
  13. / Z! R* s8 q' v. l  |, g7 N$ L9 z
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    & f; c- K" @5 H+ k, z# w- `
  15.     $dbuser = 'root';            // mysql用户名
    , p3 w- J% L& `' k
  16.     $dbpass = 'root';          // mysql用户名密码
    " r6 r# E/ J5 R* C( s: q
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    8 p: l$ x# r8 b
  18.     if(! $conn )
    " V7 Z( @% F' ?# k. r
  19.     {
    ( y0 W& i4 J& H6 o# b; z( ]
  20.         die('连接失败: ' . mysqli_error($conn));
    . U  g" Q/ k2 t* s8 j1 r8 {
  21.     }$ u# j2 j  d6 Q& Y/ ?, N0 F  ~
  22.     // 设置编码,防止中文乱码
    3 n. L/ G3 E% ~: s' M$ P
  23.     mysqli_query($conn , "set names utf8");& ]3 T* S$ m& |
  24.     mysqli_select_db( $conn, 'temp' ); ( g+ c$ z1 W5 ^; y

  25. # p9 s, V; E) Y
  26.     # mysql 锁
    - H) P$ _% P  |  Z' N# h
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 : h& I4 _6 k, t3 U
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    8 t' T; B' x: u- k# ?4 Q$ E. O! Y5 e
  29.     $id = mysqli_result($rs, 0, 0);
    2 g& a  z" z, i2 |4 U1 T9 J' k
  30.     if($id > 0) : p4 e/ b3 b: j! u2 V! ~0 W
  31.     {
    7 A& f: {5 [) N; v% o- ], ]/ e
  32.         --$id;
    3 \  [$ E2 W7 I) d
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 9 l+ Z! p& `5 ~& d$ i9 k
  34.     } - X- s2 o3 T: O- }/ q
  35. 2 P) y2 y3 }3 V! |0 @7 a
  36.     # mysql 解锁
    $ ]* I# [0 n$ h* ^
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ) f5 {( R4 ]/ t2 n6 K6 c
  38.     //查询解锁后的id值: }3 ?$ `; b1 m" _* U4 r! B" T. W
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    * b) Q  D, \: @
  40.     // while($row = mysqli_fetch_assoc($res))
    ) T) [# G! y1 |/ z6 S9 X( D
  41.     // {9 ^5 T& A8 ?8 w$ a) ?! |4 k
  42.     //     $id = $row['id'];& A4 M. r* u; L8 r
  43.     // }  h) s8 l$ h; @( P
  44.     // echo $id;
复制代码

6 Z0 n: Y/ _* [% ^
/ Z7 j% y+ A) U0 q

- W. W$ O' @# M, B0 l4 Z0 U
PHP文件锁示例:
  1. /*
    4 ^, T" s9 t3 S5 n% [* [; d
  2.     模拟秒杀活动-- 商品100件; S' ?! X6 S1 I3 j2 h5 E7 @
  3.     CREATE TABLE ta
    * n: Q2 _1 C5 I( h5 Y
  4.     (+ r: t+ I; Y8 [0 q. S
  5.         id int comment '模拟100件活动商品的数量'* G# V/ }/ S8 `6 j% x7 p9 }
  6.     );! h% Z1 s% @* m1 g5 x) e- |' h
  7.     INSERT INTO ta VALUES(100);) o9 j& C4 G* ?; A
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    . w  [! k7 q$ @& _5 {
  9.      */
    $ R: E9 l4 Y* n# H! w7 ^$ C
  10.     $ v. F6 d% W# `; _" J
  11.     // 关闭错误报告8 ~$ h. x& j' ~# R  Q4 S
  12.      error_reporting(0);
    , {# {! h, ^4 y) J

  13. : M+ E2 E% m( X6 o! F$ d
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址7 E: g( b9 e6 p7 u3 {& e( i9 h" }0 \
  15.     $dbuser = 'root';            // mysql用户名- S$ ?) |% G: q; }5 O# n( @: C! ?
  16.     $dbpass = 'root';          // mysql用户名密码
    $ B& O$ M4 U/ A& C% `- C% k
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);1 {4 G- X- x$ o' ?9 f" d
  18.     if(! $conn )
    # I2 N/ T+ E3 P" t) I* r
  19.     {
    + z9 m% q; r* l! e% r5 S
  20.         die('连接失败: ' . mysqli_error($conn));
    ! N5 U1 A9 {: u* R9 _
  21.     }) G! x1 u/ u, n# T' \4 w
  22.     // 设置编码,防止中文乱码9 N8 o1 u7 a/ p5 A+ M
  23.     mysqli_query($conn , "set names utf8");9 ^- O7 Q7 l* {0 n
  24.     mysqli_select_db( $conn, 'temp' ); 0 Z- |9 Z; X- I7 V; w4 J, |
  25. 7 b8 E5 f3 b# m1 S0 @/ n  c6 N
  26.     # php中的文件锁 5 m2 y) [* h/ L7 |: Y" Y' s( k! a
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    7 j- P# S( j) F
  28.     flock($fp, LOCK_EX);// 排他锁
    ; Q! S. j0 I4 |
  29. , k; ~9 |/ j( m7 ~% h
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    % A* R* b' A: s1 p1 h" C9 Y
  31.     while($row = mysqli_fetch_assoc($retval))
    + N9 K- T3 I  h/ f* M0 w' K
  32.     {
    % X6 l# S4 F; U* ~7 q+ H/ _( d
  33.         $id =  $row['id'];
    % Z+ x7 e1 F. j" H
  34.     }6 `! M, b/ U. W5 b: i% W- e6 l  S
  35.    
    : j  s2 H8 t  z0 z. X9 X1 H/ g
  36.     if($id > 0)
    - h3 R6 R4 Y- W5 z! g! v& Z- p
  37.     { $ f, L. c4 s1 y$ f5 F4 S. y4 ^
  38.         --$id; ! b4 P! ^2 o1 l
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);   W, c: l# O1 S/ m/ ^2 P
  40.     }
    * V$ k3 f9 t' I7 k; H, d! {: u
  41.     # php的文件锁,释放锁   O# m- b# V4 ~9 L( \
  42.     flock($fp, LOCK_UN); 6 i, [. i4 X, i
  43.     fclose($fp);% y6 m0 s8 k; w7 n4 L
  44. ! W) p1 B) ^! h  S' c: T
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');, p. |2 N, h; z! D/ |* p9 A3 w3 B& C
  46.     // while($row = mysqli_fetch_assoc($res)): s4 j3 t; _8 K
  47.     // {
    2 @2 `+ V7 V$ G8 u0 O
  48.     //     $id = $row['id'];
    7 M, b4 X: b/ @! B
  49.     // }
    " V9 H- o: J8 v6 a3 c
  50.     // echo $id;
复制代码
1 t  W3 i/ H2 ~$ g5 Q# `' }
4 m1 F7 V: B" N# S
抢券活动实例:
  1. public function envelopeSnatching(){
    * ^, {. c& _( a! d( O
  2.         $lingqu = $_POST['type'];
    7 a, V$ n6 m+ `2 g3 i
  3.         $uid=session('u_id');//用户id
    6 u; r4 ~4 J% ~
  4.         if(!$uid){
    4 z* m1 }: k) L; e
  5.             $data['msg']='您没登录,请先登录!';% N. h: F7 G$ Q6 p+ e  b1 V+ [
  6.         }else if(date('Y-m-d') != '2017-12-12'){' d$ A9 {: C% x: R/ i0 @; A) V
  7.             $data['msg']='不在活动时间内!';( L2 m& q; l6 c8 p) t
  8.         }else{  B! j# }: \2 I" S
  9.             $hours=date('H');//当前小时数
    . K: u( q& ~- B7 k- ^
  10.             if($hours > '09' || $hours > '17'){; G( o! t7 e: @0 Y- ?
  11. * @6 |6 ~% j" p, O$ G& H
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    * U& \; N; o1 Q" W
  13.                     if($lingqu == 1){2 t- J, i2 F* X3 w$ }+ `
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    * W6 s# O5 R3 }3 c" L. N9 r- F9 T
  15.                         if($hours > '09'){
    , S0 U1 k& k! V) E3 c# H; ]
  16.                             $num=mt_rand(25,28);//优惠券金额3 y; T( A  [- x- n6 I' H8 d2 _" q% B& l+ a
  17.                             $id=1;+ V9 j+ U/ X( b2 T* e
  18.                         }3 k! d* W2 _$ l' p' D  w" n2 b
  19.                     }else if($lingqu == 2){
    ; y% X3 j3 p4 h4 w* \/ l
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();: O( i% r4 T4 j3 A/ M7 V- h
  21.                         if($hours > '17'){; {% {) S1 `4 I" ~$ k
  22.                             $num=mt_rand(50,55);//优惠券金额
    ; Q1 n8 D, p% Q1 v8 Z
  23.                             $id=2;
    2 ~' B& F% N9 Z1 y' s
  24.                         }* A+ A% |, N) z
  25.                     }
    % c8 z# e7 }8 g6 {% m
  26.                     if(!$id){
    8 q3 T# m( n, K# p' }- s. r
  27.                         $data['msg']='时间还没到,晚点再来吧。';& M7 l& G( l9 i6 o
  28.                     }else{6 ^& K, T' h! |/ V- b2 \# ]' I. A
  29.                         if($is_lingqu){
    ) g  |/ H4 ~, A' H: {. Q( b; x
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';2 M* E* [  u6 {  M
  31.                         }else{
    8 P7 G  y" K" Q# ~" X# F. R
  32.                             //锁表
    3 x3 ]* w: W1 v
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');2 I0 F) y/ N" D% a
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    + v- u: J$ o) T
  35.                             if($active > 0){
    8 l7 V8 A4 I8 N2 }% f- \: k, w
  36.                                 //开启事务
    ) ?6 x6 Q) B( g) A( X( k
  37.                                 M()->execute('start transaction');# a* ~9 Y3 G7 @6 Z* B
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    5 k+ S5 K: k% b0 e: ?  f( P5 W# j
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));) j1 S. X% T4 ~! \& n; K* a2 d
  40.                                 $members_preferential    =    M('members_preferential');4 Q8 D5 e, h5 E. H9 ^" c. o
  41.                                 //对应投资金额,/ i, A9 V1 U, @, F. ^; H- ~6 u  B
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));! N# w' z0 V6 p" n* v* V
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    . e. E: \1 X$ a6 [1 z! s
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    # J1 c1 Q( V( x$ H. X) @
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
      X+ u, g  C7 s+ D
  46.                                 if($save && $add && $add2){
    ) }8 f: ~# d7 ]- b$ n) E
  47.                                     //事务提交
    & ^2 v  x& ~6 C+ d& m# @! c1 o
  48.                                     M()->execute('commit');; Z% ~% m( w( Z3 b
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    , p7 t4 O; c8 A4 _7 s
  50.                                 }else{3 a" t  z2 }1 `3 x
  51.                                     //回滚
    / E' U8 t' W' v! k( _0 c
  52.                                     M()->execute('rollback');
    : L$ G6 ?# j; U* S# J2 [: H) @
  53.                                     $data['msg']='未知错误!';1 f& n4 G* q2 J$ I
  54.                                 }
    : p/ E: g7 ]& u2 N" Z
  55.                             }else{
    , s2 y' J) R6 W( n( ]$ p( F0 O
  56.                                 $data['msg']='红包已领完,你来晚了!';
    7 F3 K& g* P, w: j% r8 g$ I
  57.                             }' q, \3 x4 f$ L5 M. |* C
  58.                             M()->execute('UNLOCK TABLES');2 d% J2 ]6 r6 X; {. m9 x# Q6 B
  59.                         }
    ' \5 A, V$ U  h
  60.                     }' M0 e: L( a) {
  61.                 }else{0 v; D& f$ r/ d# l0 e3 o9 I
  62.                     $data['msg']='非法操作!';
      b0 W& `$ B- F( a* _
  63.                 }" r( u% W1 u( E. b7 W
  64.             }else{
    0 N! c7 q6 e3 b$ }% b/ O/ v
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';6 e5 R+ v$ R0 w# {' j7 W
  66.             }
    9 N. o6 N9 j8 ?" R
  67.         }' I. o% ]" I. q9 Z. S2 [
  68.         exit(json_encode($data));1 q' Y6 I/ @: h3 q0 r! \  k
  69.     }
复制代码

- F- z' C" _7 M/ {- m5 R" U5 S, `6 l- g: m$ @6 l
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 03:14 , Processed in 0.053735 second(s), 19 queries .

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