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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

7 y8 x' S5 H" \: G& X2 \7 i
Mysql中的锁语法:# I: `2 B) k' ]) x
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】2 w2 V, f2 W* a# o
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表! g* w/ ~9 M8 m
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
: |* B0 H0 r; T" ?; m) T8 j' y9 [注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
: z( a/ Q. |6 {6 B0 O文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。: C. y% S1 ^3 x' `; B% \1 N* E  U# i
测试时,有个文件就行,叫什么名无所谓
总结:  d. X1 f' e/ B, m
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
- f( z5 x# Q8 f. m+ h" y1. 高并发下单时,减库存量时要加锁9 r- _, K/ o) D* u4 Y% v
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    5 {9 T- O3 N+ e2 g
  2.     模拟秒杀活动-- 商品100件  P. @3 f+ w# [) w! W: e
  3.     CREATE TABLE ta
    7 ^! ?+ _9 z9 E( @
  4.     (
    3 b4 J# I/ `* z& ?
  5.         id int comment '模拟100件活动商品的数量'/ `. |% j( W8 ]4 b% G$ Q5 B% @
  6.     );
    2 E  ]7 P9 B8 G7 ^
  7.     INSERT INTO ta VALUES(100);
    2 @9 j% C' x1 b
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    4 l, R+ f; I- u
  9.      */
    ! ?( N5 b- e) K$ ?0 |
  10.    
    $ D8 d7 c# V( k) K" R4 u$ I
  11.     // 关闭错误报告
    2 }, p. y" a5 d1 ~3 y9 ]: U
  12.      error_reporting(0);
    9 I8 _. U. h  l. E  j) c/ L+ \

  13. 5 u/ f8 F4 u* d- B1 S" t* `6 k3 \6 w
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址5 a0 x( w: v+ o9 Z1 u5 c
  15.     $dbuser = 'root';            // mysql用户名
    0 q" N" V. Z% h" D
  16.     $dbpass = 'root';          // mysql用户名密码$ `1 V- `2 f5 K+ Q
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);( b$ d6 C) h1 E( n) B& y
  18.     if(! $conn )0 R$ U, J5 s6 d# r/ I- K) ~
  19.     {
    . Y2 h7 n, ~! u' @3 V! u
  20.         die('连接失败: ' . mysqli_error($conn));
    : x8 U! x% O7 y2 M9 l6 F" ^- T% C
  21.     }
    0 v& P8 S( \" j9 B; p
  22.     // 设置编码,防止中文乱码3 i* R& ?6 M0 [, ]# n
  23.     mysqli_query($conn , "set names utf8");+ F) m7 N- e( n9 H/ _. o2 s  }
  24.     mysqli_select_db( $conn, 'temp' );
    6 a( ]: e/ I: Y# l, }

  25. $ ?9 O0 M. k3 a6 w% ?, f: V
  26.     # mysql 锁 , H9 ?4 ]( G3 z1 ~" \( {8 x
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    8 o' t5 x$ ~8 ^$ B3 g
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    ) a# T3 `4 m5 V' C& G! Q
  29.     $id = mysqli_result($rs, 0, 0); ' Z+ A2 u5 R& @2 v
  30.     if($id > 0) 6 {3 ]8 F# n  j# A+ H8 w
  31.     { 8 p9 j& M2 K- R4 S7 d7 L- t
  32.         --$id; , p9 {: y0 @! I/ l8 }) Q8 x
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    ! @* J# Y9 x4 X5 W4 `
  34.     }
    * j8 E) D' R* _1 r

  35. # k# E( B: @# C7 ^! m8 Y, z
  36.     # mysql 解锁 " E# J$ C  ?: z, k! {4 I& u
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    1 c! z8 `- i* C* Y/ t
  38.     //查询解锁后的id值* J6 g% W1 ~+ u6 e& I* @. m: l
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');# |1 ^% N* ]2 ~. U
  40.     // while($row = mysqli_fetch_assoc($res))
    5 O! l8 u( g+ y& s& N# u6 v  l
  41.     // {
    ' B' U, h" L, K. @2 P3 Y
  42.     //     $id = $row['id'];
    9 @! X2 F# r( O3 W+ h
  43.     // }% [' x! y9 E* P) I
  44.     // echo $id;
复制代码
) S/ r& a1 Q- {

& A$ w* `% f; K) T: R- m

, T. u0 W) ^+ v) X
PHP文件锁示例:
  1. /*
    - A" I) {' i6 x, _  W; p
  2.     模拟秒杀活动-- 商品100件* y  s: c) x' _) F* ^
  3.     CREATE TABLE ta: b. {+ G# L* q& n
  4.     (
    * p% V5 `. J' |
  5.         id int comment '模拟100件活动商品的数量'
    7 _! C$ i$ D# I# A2 \, |
  6.     );
    - M. f7 i' i# i6 n$ j1 H1 u
  7.     INSERT INTO ta VALUES(100);
    3 N4 y! e* d2 Q/ ]& W% z9 J( w
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ' F+ ?! n- \  ]9 Q' P) W/ ^
  9.      */
    * b; q! C4 O1 K
  10.     - A. f* L+ t5 N* E' F. \
  11.     // 关闭错误报告
    3 a" S' [! ?1 ?- }) ~5 ?% U- W% i5 B
  12.      error_reporting(0); ; m1 x0 Q. q4 G: ~. w

  13. 9 F" J; N9 N- o% \3 c
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ( {) g7 F+ W; K" l7 }- f; N
  15.     $dbuser = 'root';            // mysql用户名, A5 L- G( J# P+ A* K5 T  A
  16.     $dbpass = 'root';          // mysql用户名密码
    - f$ u# z: Q+ c8 y6 J& n; z- K
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);& P3 a! V8 T! Y7 E
  18.     if(! $conn )
    ' n5 Q! D5 `, o' X4 g" b( ?6 z0 U$ K
  19.     {0 o+ D% U+ I* p, U- e: m8 b- o
  20.         die('连接失败: ' . mysqli_error($conn));* d% ?6 s: v$ z9 ?6 r2 X0 a
  21.     }: {: m) E3 e- w5 d- C1 Z6 v
  22.     // 设置编码,防止中文乱码5 A* I. h) ]$ ]- T
  23.     mysqli_query($conn , "set names utf8");! n6 y5 t8 }6 r0 a
  24.     mysqli_select_db( $conn, 'temp' );
    1 f- G* z, X  K
  25. 4 S( f3 f' G8 ?
  26.     # php中的文件锁
    6 B! s; v$ M% R$ v7 d+ B) r
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 6 u) s* d, K: X4 @  i+ [
  28.     flock($fp, LOCK_EX);// 排他锁
    . [. C( L1 f  A' p' N" ~1 J

  29. ! g2 M* a* D8 ~. {2 D
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ( t9 l  o  z  r* j3 L2 E
  31.     while($row = mysqli_fetch_assoc($retval))
    3 n$ |6 [6 N# g# b  g
  32.     {, n* l% [- B0 P
  33.         $id =  $row['id'];% Q+ s7 d: K# H* M  m
  34.     }
    ! r3 A! T& P/ P" b
  35.     % \. N' \& d$ k1 V2 e
  36.     if($id > 0)
    5 H" g* r3 v! y* T1 D! R
  37.     { ; q# w" a3 Z% L: d( f9 w
  38.         --$id;
    : n4 x, H: O  |- Z. _9 r  G. r
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    0 J+ Y1 o  ?, C1 E1 P" K, d" O
  40.     } / J( L. t, [. O
  41.     # php的文件锁,释放锁
    3 k) Z1 G, w9 M5 \( c! s
  42.     flock($fp, LOCK_UN);
    5 S2 }) v1 S3 S2 J
  43.     fclose($fp);
    / g  g, H" Z0 N/ a  l

  44. 2 A( _- T& [7 L' e: E* N$ H, r4 N
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    0 s4 Q/ ~: [: i4 J9 V3 r2 K
  46.     // while($row = mysqli_fetch_assoc($res))+ M/ a6 h1 D" f& v
  47.     // {
    2 ?- u8 ~$ D& {
  48.     //     $id = $row['id'];
    1 Y+ `  ^* m2 }* ]8 V
  49.     // }" [7 f( R" B; x1 l- p
  50.     // echo $id;
复制代码

0 r9 Z0 A& I/ N& @5 R! a
% B! l. b9 q% ?: K' T
抢券活动实例:
  1. public function envelopeSnatching(){
    $ D) _5 I' l0 w7 x/ x
  2.         $lingqu = $_POST['type'];2 a2 a+ {7 v/ h2 P  o9 Z3 q6 [
  3.         $uid=session('u_id');//用户id0 Z3 F. _% v5 n- }. h
  4.         if(!$uid){
    ; V9 D3 w* c1 q4 ~+ M, r7 q' P2 t/ e
  5.             $data['msg']='您没登录,请先登录!';2 \& K; O. X+ Q3 K( y
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    ) C, N& S- l3 ?2 t; C
  7.             $data['msg']='不在活动时间内!';) e3 R; b  l' j  [+ ~
  8.         }else{
    / T. D1 ]- S5 A3 u) w+ C, L
  9.             $hours=date('H');//当前小时数6 Y' m" Z! R* N. J) S2 M+ x
  10.             if($hours > '09' || $hours > '17'){/ ]5 {0 a2 t7 v5 I5 B

  11. ( e7 u- o3 @" j( J8 _1 u
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的) X* s0 l1 b; d8 `4 X. q) B- Y* A+ n
  13.                     if($lingqu == 1){: ^0 h2 [, d3 ?% X
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过, f1 v3 ?7 \. S. S
  15.                         if($hours > '09'){- \) n. Z* I! o" k* G9 Z" g( p
  16.                             $num=mt_rand(25,28);//优惠券金额
    1 J, S# D- ~( T8 w* N
  17.                             $id=1;
    2 v+ D1 m% ]; @6 G
  18.                         }8 E  A# v1 l" }- r
  19.                     }else if($lingqu == 2){
    % e' r! c# F% t/ \
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();$ D9 e0 K' H  f# M. q
  21.                         if($hours > '17'){+ B7 |/ `7 B- m  C4 W$ O
  22.                             $num=mt_rand(50,55);//优惠券金额5 l- j+ }3 v. I1 ^) Q7 V  a: D4 g
  23.                             $id=2;
    " O' b4 d; W- @( r3 W. h
  24.                         }
    , i+ F9 c1 {: p& E
  25.                     }
    $ J8 ~5 n$ K1 [4 V3 Y0 H2 F
  26.                     if(!$id){) X% f2 M; }; l* ]
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    + h9 N! H. Z, E
  28.                     }else{
    ! l4 J+ k( J, F* T7 G
  29.                         if($is_lingqu){
    5 F8 V$ n# k6 _9 f7 _) j
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';( Z2 N% ]: i8 l: l
  31.                         }else{9 E% N9 Y/ e. g# n% l# J; T, _
  32.                             //锁表$ j2 a/ n% B% U: x
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');1 n8 \, J; V6 m+ S
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    # B* t2 C: N. O  X; I
  35.                             if($active > 0){1 `3 x7 k; g8 p6 ^. l
  36.                                 //开启事务
    8 e! e# M! p% l& V5 i
  37.                                 M()->execute('start transaction');
    " _) b9 l. H/ g* H' C( C
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));, Q: `/ }0 E8 x8 _: u
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));% m" b  D' E" u
  40.                                 $members_preferential    =    M('members_preferential');, {0 I3 a) c7 f
  41.                                 //对应投资金额,/ D  m1 d' o& g$ T5 m$ w$ i
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));: c, a  o1 [6 ~) v% y, D5 r
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    6 K) _! S. o- c0 k- Z5 T
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间+ z8 w; U+ T& q
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券3 x- z  h1 @8 m) q  t8 M
  46.                                 if($save && $add && $add2){
    $ P/ T7 ^" @& b; C. x0 _" B0 J
  47.                                     //事务提交
    6 Z' R# l# C+ {2 \
  48.                                     M()->execute('commit');
      U( Z1 w* T3 x+ \7 K7 Z
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    + E& z- U, C2 L, `* w
  50.                                 }else{( U2 s, W% s  S
  51.                                     //回滚. m+ n6 G2 I' V8 U: I
  52.                                     M()->execute('rollback');
    2 e2 |: z! @9 ^- A1 [
  53.                                     $data['msg']='未知错误!';
    0 G$ V% I: |4 ^& @) d9 @
  54.                                 }; ?7 \+ L" C  g& u2 N$ k" S* L
  55.                             }else{# a/ w2 p7 |8 L0 C7 e
  56.                                 $data['msg']='红包已领完,你来晚了!';
    7 {4 v5 d- Z5 n7 G/ v% s- J1 v
  57.                             }
    $ ^. M, e/ N) k: y8 u( q0 V
  58.                             M()->execute('UNLOCK TABLES');8 c" l5 R$ l: o, k0 n+ ~8 E
  59.                         }
    $ j4 z& W3 m8 M; _5 s
  60.                     }
    7 d' g" J3 L% |7 u) Y% I
  61.                 }else{( V% a  w& ~* p# J
  62.                     $data['msg']='非法操作!';
    % e- L: @$ z+ r+ z& J' f" K( I0 P
  63.                 }
    , X2 ]( D- F: V" j
  64.             }else{
      @* ]: I3 M9 a7 D# S7 u0 K
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';1 }. C3 q. A: v' v& N9 j+ S
  66.             }$ i9 O7 Z  ]4 r9 Z( j8 P8 B' k9 U9 R' v
  67.         }2 n: N7 Y3 ]7 H# f7 i, Y
  68.         exit(json_encode($data));
    6 {$ b0 M% U  K( _  O
  69.     }
复制代码
0 w$ K$ K. v- V

; }: D8 Q6 Y8 G% E  \% L% b
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 07:06 , Processed in 0.054573 second(s), 19 queries .

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