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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

* @( K4 P: O% Z# u
Mysql中的锁语法:" F2 e$ ]6 x  {; n- V
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
* G% }3 ]9 X9 QUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
0 V5 M. y6 ^. |' x% h9 kWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞0 T3 `6 Q6 d1 b% X' C
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
% h8 P7 ?8 ]) w文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
- Q( t4 X, t9 A1 d( r+ [+ W测试时,有个文件就行,叫什么名无所谓
总结:6 c* K# }1 m3 x% h. t
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:7 I7 ?; f, p7 w! O0 y4 l
1. 高并发下单时,减库存量时要加锁
, R. k, l. |$ V! }3 A+ r# E2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*: P; m4 b2 l" o  `5 V$ {$ s$ F
  2.     模拟秒杀活动-- 商品100件
    " R" \2 {, V. |3 ]" J" C
  3.     CREATE TABLE ta
    ; [7 d+ S$ P+ x$ r- W1 U5 A
  4.     (
    ' k4 {& d0 l9 X
  5.         id int comment '模拟100件活动商品的数量'2 z+ F: c8 a- B* r# S" X
  6.     );
    / ?! P; j" I- i# `
  7.     INSERT INTO ta VALUES(100);
    " r5 u& ^: F8 b/ @  f$ l) s; i5 b
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件( {1 L5 E- v. S9 e/ j. D
  9.      */ & V5 R/ d8 J: Z( j) d, D0 B
  10.     7 m( l% }1 g+ W& @6 \& \
  11.     // 关闭错误报告+ ~0 G! u3 b7 o* C" S0 k
  12.      error_reporting(0);
    # b: Y4 K5 y$ A8 H) D
  13. 3 Q# G) T3 ^& d& h( X# \; D
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* n7 F) t/ o4 S; I* d- T
  15.     $dbuser = 'root';            // mysql用户名7 D7 r" X9 H/ p
  16.     $dbpass = 'root';          // mysql用户名密码
    8 e- o* G3 ^8 ?  O& l; A) U
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);; J; o) B& C7 h0 i3 ?. F2 x5 v
  18.     if(! $conn )
    ) Z, o) j. Q- e
  19.     {. S7 M4 W$ D* p0 v
  20.         die('连接失败: ' . mysqli_error($conn));
    " W# L; S9 s1 x0 h7 M; r) u
  21.     }. I' y& I( h  S% T+ G2 S5 [, j
  22.     // 设置编码,防止中文乱码+ `% F) m! ~) S; j: I
  23.     mysqli_query($conn , "set names utf8");- u- D. l( q9 [. Y9 p
  24.     mysqli_select_db( $conn, 'temp' );
    2 U. j8 |) V4 N5 b; m' `" [% {/ x

  25. 3 _! G) u7 Q  n) u' Z& ^
  26.     # mysql 锁 " C, u" M! e. N
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    3 h, q$ Q: D' U+ e+ ?) f
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 2 _% t0 d7 V( L
  29.     $id = mysqli_result($rs, 0, 0);
    & K" W9 _7 {) l9 m. s# f, |
  30.     if($id > 0) 3 b( s* B" g/ p6 Q5 X" T+ Z8 ~+ O4 ^
  31.     { ! v2 Q6 d; T  e2 p$ H% t
  32.         --$id;
    . ?' B- L5 ^* z2 t1 C/ b
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); / v# L$ m7 G: D. D# r/ K
  34.     }
    ; @, {9 s5 B+ @. x

  35. + d  P" y1 T8 v* A' \* J1 e6 k( f2 X
  36.     # mysql 解锁 " P2 U0 w+ \; w/ k1 P1 b+ ~+ Y
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    . P9 ~8 S% z- C5 ?: ~, G8 `# s9 N: B
  38.     //查询解锁后的id值/ J! o, S* s9 g/ Q
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ! g# f: ^' t1 ?( U- J# J1 Z
  40.     // while($row = mysqli_fetch_assoc($res))% D7 f" F" |0 ?1 [
  41.     // {
    $ r$ V$ ^( v8 o( |, _$ F9 E
  42.     //     $id = $row['id'];4 z, H+ U# m1 O. M2 o; O
  43.     // }
    ( b& v4 G* {5 s
  44.     // echo $id;
复制代码

. [( _- p. Z2 B  S6 M( e( l( Y3 s5 w; v3 i9 B" N2 i, q
  C) Q  X# Z0 L% z0 U
PHP文件锁示例:
  1. /*
    ; o# H1 w3 j" \, A- h
  2.     模拟秒杀活动-- 商品100件
    ! I0 H( o) b& e. ?/ m3 a
  3.     CREATE TABLE ta+ \: L6 T9 y' d* G% r3 @( l  }2 i* d
  4.     (5 m+ K4 w( _5 w. G4 G1 M
  5.         id int comment '模拟100件活动商品的数量'
    ; M; R* U& m* ^7 _- O
  6.     );
    $ u4 r) [$ A- O
  7.     INSERT INTO ta VALUES(100);  t" X. H7 d1 {& \3 R9 J8 G
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    1 J) b$ j9 c* [! A" f
  9.      */
    2 r2 i, n/ \) V6 _8 J$ Z
  10.    
    8 V* y/ }% ?& ~: v( z9 n0 W2 O
  11.     // 关闭错误报告; Y% N& g7 }' N4 D
  12.      error_reporting(0); ' W# {4 f+ ~8 Z7 J  r

  13. : k9 _0 v# R4 Y" g0 h
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址! `+ u# T6 P5 w& M2 Y
  15.     $dbuser = 'root';            // mysql用户名
    ' d0 G8 d% D, q7 r
  16.     $dbpass = 'root';          // mysql用户名密码
    $ J* c" W  P* s% b
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);2 @2 K* q9 d% ~& V
  18.     if(! $conn )
    8 c* l$ f6 ~' s% B
  19.     {
    : H1 F, k; k& t! C* o7 Q
  20.         die('连接失败: ' . mysqli_error($conn));
    # Z* A1 w" R1 R+ x. v9 J
  21.     }+ r. ?" F) T) C6 x8 q( v8 k
  22.     // 设置编码,防止中文乱码7 J/ S7 S- H) c" C, t3 _: Q9 H
  23.     mysqli_query($conn , "set names utf8");
    . ]: `3 c' b) ^; b% R
  24.     mysqli_select_db( $conn, 'temp' );
    5 S  W1 `$ e2 ]7 e  q

  25. / ]4 R1 m6 ?0 X9 m4 j, J
  26.     # php中的文件锁 / s3 g1 j1 F2 [
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    ) k0 _) E' p0 Z
  28.     flock($fp, LOCK_EX);// 排他锁
    # V  W, k, M" d4 l* f5 {
  29. 3 r- T% J1 Q2 i7 S0 v/ A6 w0 J
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); # Q0 e4 x0 S( I8 ~
  31.     while($row = mysqli_fetch_assoc($retval))
    , ~1 W, G: e% P2 L" |; j  B% S0 \
  32.     {( I- T; L) I8 P# l9 c7 M; k; n
  33.         $id =  $row['id'];% M/ V$ D3 V7 ]0 i) C! N9 s5 m
  34.     }
    ' r( I7 _# B. {& {0 k8 O3 z7 t
  35.    
    ( h! }8 m6 ^7 ^
  36.     if($id > 0)
    - d8 j! C1 o, k+ d2 `+ N
  37.     {
    $ x7 [( p) T, H2 Q7 g+ z9 ~
  38.         --$id; ; s' e# g! X+ z# w) j
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    & D) N2 Q) x( h5 u
  40.     } 4 s8 \! p9 w6 X+ K
  41.     # php的文件锁,释放锁
    ' L4 A# @4 l: E5 G9 W
  42.     flock($fp, LOCK_UN);
    / C# v. z- i2 R9 _( X7 U
  43.     fclose($fp);
    / ?" u* m6 R* C. p# Y6 k* ^+ V6 ]

  44. 6 K7 }* P! C5 A8 F/ A) c: C7 |; G
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');+ k- S4 O8 y, X1 I. j- W) K8 a% z
  46.     // while($row = mysqli_fetch_assoc($res))7 D! ^2 Y6 s: S+ v1 W: P6 Q* X
  47.     // {
    & T$ l8 K! l8 a$ h* H% I6 h& [/ X' r
  48.     //     $id = $row['id'];
    / G" y! e0 w0 F, A. v
  49.     // }
    6 l( @8 R4 t. l, S$ B0 d- E) Z. e
  50.     // echo $id;
复制代码

2 v+ i7 F' W) r$ x* j: \: i& a% y; L, B1 C9 R. }/ V+ M
抢券活动实例:
  1. public function envelopeSnatching(){
    " t- @* G' F& G6 q0 @0 z; Z
  2.         $lingqu = $_POST['type'];
    & `' k& B8 C0 \8 N
  3.         $uid=session('u_id');//用户id
    * I  m3 X" z! ?" d) u# [
  4.         if(!$uid){
    0 U8 k0 T: ]$ ]" S
  5.             $data['msg']='您没登录,请先登录!';
    6 B# I  U+ K+ c4 r3 \/ ?
  6.         }else if(date('Y-m-d') != '2017-12-12'){, p( {( V9 N7 ?7 a# q. ^- p
  7.             $data['msg']='不在活动时间内!';% ^* r, B3 Q! _! y
  8.         }else{1 z* i& J; N. v7 k  v9 X( S: o
  9.             $hours=date('H');//当前小时数
    " |" Q$ X. R. C
  10.             if($hours > '09' || $hours > '17'){* X% b, U, [1 q3 V2 y. M. s

  11. % h  S' z5 F; K9 ~5 E
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的% v. \4 ?! A  K& K/ c  A" s
  13.                     if($lingqu == 1){
    $ @' W. s) Y: Z. Y2 d
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过+ b4 z6 G3 J7 I+ E1 Y! T. [+ s
  15.                         if($hours > '09'){
    # h$ B. t2 r: i  N% K
  16.                             $num=mt_rand(25,28);//优惠券金额
    ! R0 H6 T' @- Y# X$ m
  17.                             $id=1;( x" x, K" }9 t4 q" A" K
  18.                         }
    8 I- W: f1 Q* m1 G
  19.                     }else if($lingqu == 2){$ W5 o3 S9 `0 l  I. P: @& `7 K8 W) w
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    7 w* p7 g) b' z" d
  21.                         if($hours > '17'){8 T: O* D8 L( `
  22.                             $num=mt_rand(50,55);//优惠券金额4 G- z4 X5 i3 Y  X7 x5 q! E; }# \
  23.                             $id=2;
    1 }" _4 j( o* C* j
  24.                         }8 ^0 @7 Y3 `  a5 e6 P, k
  25.                     }
    7 P) O% _1 l/ f! P- T% {- t
  26.                     if(!$id){
    2 w1 I; }2 Q5 m! A1 U# Q
  27.                         $data['msg']='时间还没到,晚点再来吧。';4 ^. A3 t4 R5 C! J" ^! ?' T& y
  28.                     }else{
    % K( M: k) l& @7 f9 K3 R7 l
  29.                         if($is_lingqu){- H7 h' Q+ P/ t' R* v9 x- W
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';0 b1 b+ |$ a' [% S  C5 T. P
  31.                         }else{* t. Z8 ^0 ~4 V% g
  32.                             //锁表& c0 M! i) x( y2 L" I. E
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');+ J0 o- p+ f' i" w4 e
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();' y: G- y1 s2 C
  35.                             if($active > 0){0 E' P* x! R0 S$ ~
  36.                                 //开启事务( v2 q5 l6 n# \4 h5 m: m
  37.                                 M()->execute('start transaction');
    4 c  A6 ~8 R! a$ T% C/ b) p$ l1 C8 J% E
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));- r3 W1 {3 J* m& I" l* z- v
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    ! @. A$ K; X- ^' b4 t" z
  40.                                 $members_preferential    =    M('members_preferential');$ k: z- J9 q0 \% Y: @7 r. H1 l
  41.                                 //对应投资金额," x* G% b4 q8 h& j( ^. _4 r
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    + V9 |1 |7 Z: `  r
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');* o- v2 L: q$ G# c
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间( B! F; [0 M- Y& h, V2 w5 ?9 g- {
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    & G. Y/ v7 t% g
  46.                                 if($save && $add && $add2){6 p8 y/ L2 y7 T" X
  47.                                     //事务提交
    3 A  v* T3 b6 \0 L  o
  48.                                     M()->execute('commit');+ J4 t7 S2 F- w! \2 G
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';# b) a$ h8 K! F) S
  50.                                 }else{2 m# {5 d$ g* k" J* K* q
  51.                                     //回滚8 f1 w+ t$ p  F/ {
  52.                                     M()->execute('rollback');
    ) C7 n7 `& u( |! g9 {  a* {
  53.                                     $data['msg']='未知错误!';
    8 x% N/ W4 X" ~$ u
  54.                                 }
    1 L0 _8 k, t$ L6 j  @9 w
  55.                             }else{
    $ N& `( Q( y- r3 l0 J3 ]0 U% d1 x
  56.                                 $data['msg']='红包已领完,你来晚了!';
    1 N0 V/ d, @8 t. {: M3 e1 |
  57.                             }, W/ L5 E* v5 ^) _! S% O% [  L
  58.                             M()->execute('UNLOCK TABLES');% _# [3 P& z) R7 l1 z
  59.                         }$ T% e$ D) j$ X+ U) V% ?
  60.                     }1 b  r+ E- A" {- T& A! M2 ~$ m
  61.                 }else{
    / J( @  w1 t5 {6 S5 A
  62.                     $data['msg']='非法操作!';* A4 B% w/ R# o  K; ^
  63.                 }
    6 \9 E5 _8 t# a. z9 t
  64.             }else{& |/ _6 x$ C# [; A) `
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
      E% w8 z( V' H2 I* u
  66.             }
    % L9 N, j6 r* L5 J1 \$ y) |2 p; S
  67.         }7 e" V, E9 D. o6 m( e4 p" I+ I
  68.         exit(json_encode($data));
    4 C- F1 ]& U4 C
  69.     }
复制代码
1 F; @( B) {' M) j9 U+ o1 U* i

4 {' {; R, E3 G- z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 21:27 , Processed in 0.112820 second(s), 19 queries .

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