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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8717|回复: 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://请求的脚本
复制代码
; P8 o8 l: F7 z! A
Mysql中的锁语法:
7 }! r5 g( ~$ ELOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
: ?- [' D# s% r2 Z: e/ pUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表5 g" Z5 ?, `- ?- u, P
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
) y/ P* q" G; }  V& |. D- I注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
! D5 O  B. E, K" Z% T* f文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
) h+ w& Z" z7 R* H: u测试时,有个文件就行,叫什么名无所谓
总结:% i& l5 I. `2 A. o
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
7 y- X1 J1 m/ b! B6 A/ F" u1. 高并发下单时,减库存量时要加锁
7 Y( R9 c( [/ o. R2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    + A7 l+ k9 ]5 U
  2.     模拟秒杀活动-- 商品100件
    ' Z7 a4 B! S3 N* h* \
  3.     CREATE TABLE ta
    / ~, Y' o  I8 |) Y1 @) ?
  4.     (8 P, X: T5 d; |5 S% Y1 V. g
  5.         id int comment '模拟100件活动商品的数量'- f) j1 O9 W& n3 z7 G
  6.     );* L. ~: S& X& b$ _! h1 c7 l4 ?5 `+ S: B
  7.     INSERT INTO ta VALUES(100);
    3 Y5 n4 M% s  U' g
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    # l. ^  N5 S* {. i' b8 Z
  9.      */ + C. |+ A( x8 n+ v( \
  10.     + ~; b( J+ \. `2 q0 d$ x
  11.     // 关闭错误报告
    , o8 {% W+ X) v2 A- b7 D: u
  12.      error_reporting(0); 7 c. O1 `+ C6 n

  13. 3 T- d$ O6 n+ E% l6 q' Y6 y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    * K  P; f9 j3 A$ e; p
  15.     $dbuser = 'root';            // mysql用户名; s* a3 p1 s# e. B; B7 b/ d
  16.     $dbpass = 'root';          // mysql用户名密码
    / Y& H* O  G- E* G' }! u* ^+ f
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    3 K# c! G4 _& E, H6 p3 W) u: K7 ~
  18.     if(! $conn )% E9 o% `. @. o, h8 R
  19.     {' {; L0 Z1 U* M# f3 q
  20.         die('连接失败: ' . mysqli_error($conn));
    2 H. e% t" b# y3 p$ [
  21.     }
    ! |9 e. w# H0 J8 _) }) \1 ]
  22.     // 设置编码,防止中文乱码, c+ k: v2 \' i8 V( E
  23.     mysqli_query($conn , "set names utf8");1 m" E( ]5 T8 h- M6 V* P: O: X, j6 U
  24.     mysqli_select_db( $conn, 'temp' ); 0 S& Q2 I, Z9 z1 t1 F: i& ?$ ^  ]

  25. $ M" x- J' a% b! W; e
  26.     # mysql 锁
    ! M7 _5 L+ w1 g- p, A  S' o
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    / V3 T& B/ Z8 C, w
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); : F% z0 ?) t* j# Y6 ]5 L
  29.     $id = mysqli_result($rs, 0, 0); ' v$ \& C( `% G4 T% a
  30.     if($id > 0)
    4 D- s6 |% i0 P+ G; l. S5 ^
  31.     {
    , z4 ]4 K, }: h# ?8 ?
  32.         --$id;
    " @3 M$ x2 b$ y1 ~; D& E9 a
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); - A( P: C) F' `5 T6 j
  34.     }
    , g1 W) W3 D9 S' n- `9 a& G

  35. ! R/ \4 r0 k' e. g- S
  36.     # mysql 解锁
    / u/ U9 q0 _2 W9 k9 t% E! D
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    " h8 c: N- v) U0 q/ |* G
  38.     //查询解锁后的id值, g9 Z  R4 R! P6 u& v* s
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');6 ^* v/ R( \2 Z' R9 t9 k1 d
  40.     // while($row = mysqli_fetch_assoc($res))6 l+ ^! A; T# G+ f* x
  41.     // {) ^2 R; q9 s+ [! V. @# p
  42.     //     $id = $row['id'];
    4 I- j& v' O$ Z! p
  43.     // }
    " O1 B6 r2 M8 f2 \
  44.     // echo $id;
复制代码

3 ^, @2 C3 A* _; K1 k' c
3 x6 c7 j9 w. N
; F' Z' `; ^* M: W3 l
PHP文件锁示例:
  1. /*
    . i" H, V* p) a# T) C' ]
  2.     模拟秒杀活动-- 商品100件
    8 Z# B! J' n5 q9 H8 W/ Q
  3.     CREATE TABLE ta6 y5 s- Y# t* ?2 J7 m7 ?* c. f
  4.     (
    3 g& |* Q2 y2 |6 ~% P% ]5 ]
  5.         id int comment '模拟100件活动商品的数量'
    $ N6 o3 h+ f9 i# o% p9 }
  6.     );
    ! Q2 ^" y0 i; M  D3 z* H. {7 R4 ~
  7.     INSERT INTO ta VALUES(100);
    1 o' X5 Q* ?( T# t! v8 j
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    5 N$ l* C7 j$ t8 o' \+ p
  9.      */
    : Z* |. m% }, A+ A' W! s- B
  10.    
    " ]! j6 C9 n  ?  c* B
  11.     // 关闭错误报告
    ; S) Q" Q6 D( T2 U; q1 d7 A" z
  12.      error_reporting(0);
    4 h5 e! m: C3 m0 Q
  13. 3 @) s+ g3 ~7 u! Q! n
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址5 ~$ U  e" c: O; U6 ]1 }6 z7 M
  15.     $dbuser = 'root';            // mysql用户名8 L' S- i) L- h+ @- W
  16.     $dbpass = 'root';          // mysql用户名密码2 b# W( ^2 n, [( E( C
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    * K. b  z: q3 b2 K
  18.     if(! $conn ). T$ y' x7 l+ K( }% L+ o; Z
  19.     {/ T' p+ F2 T9 H4 D) R) B
  20.         die('连接失败: ' . mysqli_error($conn));
    * l7 D8 v2 Q  ~6 a. N
  21.     }
    - s( j9 r4 E( b- J- ]
  22.     // 设置编码,防止中文乱码
    7 H# g5 s. t+ k. P- y7 k
  23.     mysqli_query($conn , "set names utf8");4 e' U, q2 ~  o
  24.     mysqli_select_db( $conn, 'temp' );
      a, E) J) V$ ~  R7 _
  25. ; _' d! ^9 R: ?6 P& }# l
  26.     # php中的文件锁
    % X8 t3 V2 q  |$ L$ m  C
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    0 r1 w  V# \& W& y7 a, t7 M7 X
  28.     flock($fp, LOCK_EX);// 排他锁
    + [9 O% S/ L! {6 `
  29. % U# C5 e+ V6 u+ z$ G0 G% t% c
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 2 f8 w0 f! X" `6 B6 G
  31.     while($row = mysqli_fetch_assoc($retval))/ r- F/ U/ c4 Q, r
  32.     {
    2 s- v( w/ m/ w' t# x
  33.         $id =  $row['id'];' Z. e4 q/ h  S6 ~+ ^& k
  34.     }. U! H3 f$ H% m8 M
  35.       i) f7 I2 a% m/ c  T
  36.     if($id > 0)
    " ~$ [7 w3 N9 I
  37.     {
    1 {( ~/ I) j1 F  _& H
  38.         --$id; " ?# ~; q$ V5 c$ S2 W
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); $ R8 P+ {; z" x2 N& y; e
  40.     }
    % w4 B: v0 q. ]& }) \
  41.     # php的文件锁,释放锁
    - d  T) S: ]( I7 x" h! j8 D
  42.     flock($fp, LOCK_UN); 5 w' C+ R+ J4 u! q( g2 g& P
  43.     fclose($fp);
    ! I0 w( q& F6 B' E- T8 \! J

  44. 1 T8 l1 ]6 Y' f. s
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');# P% i- b0 {5 _) W
  46.     // while($row = mysqli_fetch_assoc($res))
    ( S, M/ W, D9 |% j; }# I
  47.     // {& ~" O' u$ Y% A4 i$ ]5 S+ Z
  48.     //     $id = $row['id'];
      U. v- i; K2 q9 W* D/ N  c, m
  49.     // }- A- c* T! O, L6 `5 h& k
  50.     // echo $id;
复制代码
  X# F2 Y3 g0 z& `5 k+ q

/ k. B+ r! ]6 R- k
抢券活动实例:
  1. public function envelopeSnatching(){
    ! O6 P( s* m% M' a( t
  2.         $lingqu = $_POST['type'];
    ! r2 @) x! Y8 C- V
  3.         $uid=session('u_id');//用户id
    6 R) I! Y" \& n+ I0 j, e
  4.         if(!$uid){
    3 Z: Q( O& I% m" h
  5.             $data['msg']='您没登录,请先登录!';
    $ d+ n8 l' c0 x: e
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    - g* ^: J& U% m7 D8 K
  7.             $data['msg']='不在活动时间内!';
    8 c& Z! y$ J4 w/ q1 K2 C1 ^' Z
  8.         }else{
    9 N& J* p, F$ W4 P
  9.             $hours=date('H');//当前小时数
    , {( [1 h8 |7 ~6 g7 \
  10.             if($hours > '09' || $hours > '17'){& s  p- i& U8 W" r" s. V

  11. 2 c: H. e9 B- r' \2 _5 i
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的" C/ Q9 B9 t% y: s, P# h/ J2 ?
  13.                     if($lingqu == 1){
    . c  y% A( u$ b( B& K" c
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    4 A! `2 x0 A/ [7 P5 s
  15.                         if($hours > '09'){
    " h3 e+ x% X7 X
  16.                             $num=mt_rand(25,28);//优惠券金额! V- }# r) n/ A
  17.                             $id=1;
    * D* |, B2 V! i) R5 P
  18.                         }
    6 \4 ?1 [/ m/ T4 x( ]; C
  19.                     }else if($lingqu == 2){
    ( l: R) N3 t' e
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();" j" R) [3 \3 R" _9 L' d' j3 P% x
  21.                         if($hours > '17'){
    2 |1 U5 i* z$ u* ^  Y1 H1 \& o
  22.                             $num=mt_rand(50,55);//优惠券金额
    : b0 V7 D: ~# Q$ f; ^$ `+ Z
  23.                             $id=2;
    - P& K1 _6 J! x2 B8 h; B
  24.                         }1 b' }, y' ]- c+ ?% d1 b
  25.                     }* L' [: s1 Q; `( z
  26.                     if(!$id){$ R# {7 Y" t! A
  27.                         $data['msg']='时间还没到,晚点再来吧。';3 L8 b! r5 V. ?0 @: ]  D& i3 x
  28.                     }else{5 p7 |1 r5 K( A2 I; @
  29.                         if($is_lingqu){
    . }- P6 W  M, W# o  C1 E
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    % n2 u4 x$ p+ ?  a$ i
  31.                         }else{6 i) A4 I) L$ K0 q6 M
  32.                             //锁表
    / @8 H. R- m, \+ u6 D2 F
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    2 T1 P' ]$ I4 H3 T3 E
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();* D) Y; X2 {( P& W7 B3 L
  35.                             if($active > 0){, v' [( w& T/ y( W2 W' q# n
  36.                                 //开启事务! Q% j* h. r0 @% I7 X: Q: {
  37.                                 M()->execute('start transaction');' a" i4 R2 L- e# S
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));" a+ l3 X- y1 S+ ]0 l, i/ [& e
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));  K" X. f" g- G
  40.                                 $members_preferential    =    M('members_preferential');7 H$ D' x" ~3 H; y5 J/ i+ p8 I
  41.                                 //对应投资金额,5 P5 F' U. y0 H7 R1 G
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    : G' S& n- [$ }3 H
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    , B! x" d1 U3 b5 f
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    9 S" N7 a3 D* N- a$ v
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券2 K" X  u9 |- y* o% d
  46.                                 if($save && $add && $add2){. D* m# b; T/ l3 p% W  u
  47.                                     //事务提交: {$ U) X5 K3 R- n& u
  48.                                     M()->execute('commit');$ T- a* b, R! x( w% f3 }0 W3 @
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';5 W: l, q7 D8 ?& K# K9 M0 l5 m
  50.                                 }else{3 [( T( O3 ?+ E$ K6 h
  51.                                     //回滚6 W7 k( m( ^' @7 [
  52.                                     M()->execute('rollback');3 S7 U. }, r. \) R3 l" |
  53.                                     $data['msg']='未知错误!';& p6 E/ i5 g; n6 V! T
  54.                                 }+ S* G5 r3 J$ o$ ~' Z" g! a5 [% U4 b
  55.                             }else{
    : o- @% u/ u9 |" I, G# D7 s
  56.                                 $data['msg']='红包已领完,你来晚了!';% R* Q+ [- {) i& ?  _  U! K
  57.                             }" }# U. M. J. f/ D' a# b2 D( ]
  58.                             M()->execute('UNLOCK TABLES');' N. N4 |( y" d9 Z* H( s# G2 v/ b/ n
  59.                         }$ s% z# {2 R! x" r/ S
  60.                     }
    5 S" T0 {! g2 H" w& I) v
  61.                 }else{0 G  v7 V( Y1 X% B* ?
  62.                     $data['msg']='非法操作!';
    5 R) i( W4 f* b4 R
  63.                 }% u4 h0 e3 y) I* u5 p  q8 O9 Z
  64.             }else{
    ' P; R+ z$ f7 C/ G4 a) X
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';  ]0 Q3 P/ |; ^, Y9 h6 K
  66.             }, W* @  ]9 \- F- J/ K/ G6 u
  67.         }
    # v, W$ u- k) q. H  J1 S
  68.         exit(json_encode($data));
    1 N  V6 B/ I$ S5 M
  69.     }
复制代码

0 Q8 j, V4 M9 }1 V' V: A
8 }- h" u. j: A/ U% u* I: S5 v. Y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-4 10:41 , Processed in 0.074221 second(s), 19 queries .

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