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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

; I3 \) e& e) `2 x( M5 E
Mysql中的锁语法:
2 H: }/ G+ y* n# ]/ Z; `- mLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
4 a2 w9 U8 r' M" p: [' s) fUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
; h3 f0 {! A' w, E- x% a  \6 BWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞2 k% J0 r# b! F
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :6 V% w( J3 C& D. F' \3 V6 |
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。+ S3 x# S$ L: r
测试时,有个文件就行,叫什么名无所谓
总结:9 d# Z$ Y6 n" a% }, p5 X
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:. n" H- I/ e4 z7 {7 q# I
1. 高并发下单时,减库存量时要加锁- A& \, i% b, q  x0 z4 I3 |9 v
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*  p* g  h. W. ?1 l  x3 K- W& m/ Z; x
  2.     模拟秒杀活动-- 商品100件1 c0 \& `+ N- n! n
  3.     CREATE TABLE ta/ Y+ h- l6 B7 `; F/ F
  4.     (  D/ y4 R; W5 ?
  5.         id int comment '模拟100件活动商品的数量'
    " `2 p% `" j4 W
  6.     );# P2 I4 e0 I. p0 x: a7 I( [# g
  7.     INSERT INTO ta VALUES(100);; U) w' O& g9 \
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件( J6 W7 l3 w8 G3 j( |$ ]
  9.      */ & k- [: h. A/ M$ _' `. L+ T# D
  10.    
    # ], O" i% [/ b2 F/ {6 F& d0 P1 E0 F
  11.     // 关闭错误报告
    1 y: Q  h3 P' T$ g/ g
  12.      error_reporting(0);
    4 j% g1 O# Y- k1 F7 o7 G

  13. , ^* ~& z7 i6 L
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    * t" n5 P* v5 f  m" K1 _* P4 X! ]
  15.     $dbuser = 'root';            // mysql用户名- b7 s  y4 n. V' X; i3 y% K, x
  16.     $dbpass = 'root';          // mysql用户名密码  ]. T2 \9 h* F) A: U( O
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    + y8 x0 c$ M; O6 |( ^
  18.     if(! $conn )# ^& E; \) j; E1 i' A1 W
  19.     {  _4 B" S7 k( E' n& W
  20.         die('连接失败: ' . mysqli_error($conn));9 B1 j2 Z# L5 s( |9 {8 z! ~
  21.     }
    8 n. t6 b/ N% Q3 G% y) L9 f6 P$ ]( V
  22.     // 设置编码,防止中文乱码  J: K8 b! }7 o7 q5 j( ^
  23.     mysqli_query($conn , "set names utf8");
    % Q- f; y. y. i5 M9 ?: r( R) c# F: u
  24.     mysqli_select_db( $conn, 'temp' );
    6 C7 {/ \+ N' P- @( Q) o
  25. % d- ]5 h& ]' F$ o
  26.     # mysql 锁 - G" q+ m0 x6 l
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 $ l8 j0 l( [" U! d" d; r; T2 b
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 2 c9 r( f/ V: C  K3 o# R/ l
  29.     $id = mysqli_result($rs, 0, 0); ; v+ \# Q: s. l+ X+ @
  30.     if($id > 0) ; D9 J8 e: n" b0 e; x  O. @
  31.     { ' S! z  {) i7 H1 ?" i: A
  32.         --$id;
      |6 d: Y2 I5 v5 j  ]
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 0 E( g* p! [4 t4 v3 X
  34.     } , c8 c+ A, U+ o" c  ~; y

  35. 9 w, J) d+ e: B5 l1 L" p  l* C
  36.     # mysql 解锁 4 P% m8 @* ~5 G  c" \& I/ d
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    1 l4 f0 y$ ~. n8 o1 R- q- D0 a
  38.     //查询解锁后的id值
    * i! f& [2 i3 c" n8 y
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');* i0 i) t: M9 i) ?
  40.     // while($row = mysqli_fetch_assoc($res)): [' q' ]/ I5 N& a- A  Z/ {
  41.     // {
    , U% T+ A" M$ x# ?" L/ M
  42.     //     $id = $row['id'];; S# s" M* Q9 f
  43.     // }5 d! M# L3 o5 w0 x. C9 U% T% h
  44.     // echo $id;
复制代码

% i  ?) R3 X6 g+ W
! P$ |5 B/ c. `
8 ^2 h; N! c2 x; E; E4 `( n
PHP文件锁示例:
  1. /*
      {% e5 N" k% F( w; K% U
  2.     模拟秒杀活动-- 商品100件  `& m; O1 ^( b7 Y3 E6 q9 H1 v( D. z3 L
  3.     CREATE TABLE ta
    : x' A" D+ v: v/ F5 r* P
  4.     (
      }5 `" s8 \; ]2 K/ E& e
  5.         id int comment '模拟100件活动商品的数量'% j- s# x7 K$ o% x3 L' }
  6.     );, y; k1 Z" T; X2 i7 K& }! F$ @
  7.     INSERT INTO ta VALUES(100);
    . ?& w+ N( V; Q
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件& m/ l" e$ [" @
  9.      */
    0 z+ j$ C) V8 _
  10.     $ l9 S3 L" W1 R. R- D: f1 V' c
  11.     // 关闭错误报告
    5 \, y' l  B4 }* |: e" w
  12.      error_reporting(0);
    9 D7 Z. @1 {+ M9 a
  13. ; i0 y* c# `+ K4 a  [5 \- j
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    + a$ D- s' t; T9 f* l- J: G' Q
  15.     $dbuser = 'root';            // mysql用户名9 V, ]$ N) W; e/ H4 q% U
  16.     $dbpass = 'root';          // mysql用户名密码/ S) d, y4 n4 u2 P4 p3 ^( N
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);8 v: y4 W/ ^. ]3 Y
  18.     if(! $conn )- N4 I0 J& g. {6 X3 d' e
  19.     {
    % _+ B9 X) S. v# u
  20.         die('连接失败: ' . mysqli_error($conn));  C0 G- t  j7 @( M6 d+ H
  21.     }2 H- q. j9 J( l+ F. b+ A4 {1 i
  22.     // 设置编码,防止中文乱码
      j+ Y9 M; ?  j
  23.     mysqli_query($conn , "set names utf8");
    0 b6 j! h* t8 r# U9 }, v2 d
  24.     mysqli_select_db( $conn, 'temp' ); 0 O9 f6 h7 f- T1 B4 k

  25. 7 I' b* E- g6 L2 Q% a" C6 B2 N
  26.     # php中的文件锁 " ~( s: m" R; P+ b* A% k
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    5 ^2 Q; F: Q  G% ?# B
  28.     flock($fp, LOCK_EX);// 排他锁
    ' i7 ^8 m& y) |  x; m

  29. % S9 n; o9 y9 S9 U8 {, y
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    : V% L* x3 Y7 O& D7 a
  31.     while($row = mysqli_fetch_assoc($retval))
    8 _2 F7 H$ @( [; E0 I& \! m
  32.     {
    3 `$ Y2 k- y4 _4 N- z
  33.         $id =  $row['id'];3 ]% p! V, K5 j6 {; \
  34.     }1 Y  ]% e. B& H) x
  35.     6 X$ s5 H- ?$ F
  36.     if($id > 0)
    4 a# k: N$ n7 j
  37.     { : e: U7 i; D. K& U# S( M" o5 ?
  38.         --$id; . Q& v0 U7 I0 v3 P
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 7 p" b8 N% m3 w
  40.     } " z/ D1 J" k4 z) g- ^
  41.     # php的文件锁,释放锁
    ! l/ |) j$ g/ q, C/ U; @/ t/ ?' p1 @
  42.     flock($fp, LOCK_UN); , {% X/ |9 Z2 y$ r
  43.     fclose($fp);
    : ]- H$ z# z, _) n
  44. $ `" N4 p% q+ Z8 U3 k
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');  \+ o/ t' _- z/ L. q
  46.     // while($row = mysqli_fetch_assoc($res))
    7 H" m3 r, o5 z- p* M' a% B
  47.     // {' Z4 Z) f  f& p5 Y9 B* U7 D8 E' ~
  48.     //     $id = $row['id'];
    1 ^6 l  h7 |( T- K; }
  49.     // }
    " z& b# M$ U/ k- y* J
  50.     // echo $id;
复制代码
. `' l7 m; g) h2 b: w
2 z" K" h  B, N% u" D
抢券活动实例:
  1. public function envelopeSnatching(){' y% B4 P' X0 S
  2.         $lingqu = $_POST['type'];0 c/ B5 [# Z9 f5 t
  3.         $uid=session('u_id');//用户id( t2 C/ g0 p- e7 M" ~% [
  4.         if(!$uid){1 N0 |+ ]# u: \
  5.             $data['msg']='您没登录,请先登录!';8 B- S0 Q" P9 E1 t
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    : h9 Y3 p0 [  q/ _
  7.             $data['msg']='不在活动时间内!';. J; B; X4 _( |! \+ y
  8.         }else{: t2 H0 ^3 r+ J
  9.             $hours=date('H');//当前小时数" m% j1 B# `, S* W% P7 c2 _6 ]
  10.             if($hours > '09' || $hours > '17'){4 E4 [( D0 k1 R

  11. / Z5 T3 J9 I9 }, A" ^* s6 L" X& e
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的2 v7 r0 M4 G7 J1 h3 L: r
  13.                     if($lingqu == 1){
    7 v/ G: |% R8 |* V8 ]
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过8 ]# B  T/ [/ ~& a) e2 j) e
  15.                         if($hours > '09'){
    % o( C2 f% q! H1 e% {
  16.                             $num=mt_rand(25,28);//优惠券金额
    ! Q* k8 a; R6 N# j5 k/ A8 [
  17.                             $id=1;
    : ?3 J" [6 f2 `5 K! V
  18.                         }
    : R9 F+ O4 E8 K& E1 ^
  19.                     }else if($lingqu == 2){. S- k: k) [: a+ f
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    , y% t+ x( t' C0 ?( Z+ ?( ~
  21.                         if($hours > '17'){" q8 b4 k( w9 _; P! B4 Q- X8 h: ^5 j
  22.                             $num=mt_rand(50,55);//优惠券金额
    ; N2 h3 @. m- M* @! L1 Y% v
  23.                             $id=2;
    0 R  P! d5 M7 k" ~/ `( i  ?6 e
  24.                         }
    4 k/ h, _) b; ?7 ^4 z4 }
  25.                     }6 c" R) W! F! y) Y  u4 o
  26.                     if(!$id){6 [. G1 t5 B) P$ y6 n
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    $ G+ I) `0 L: H! h6 h* m
  28.                     }else{  G1 b, `+ o& l/ T7 o
  29.                         if($is_lingqu){4 I, d) J2 h1 \3 H
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';) {$ b/ U1 y) {" R) I$ t
  31.                         }else{
    . m: s1 Q- F. g# E( p' b7 S
  32.                             //锁表
    + R' p, R8 c7 L
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    1 S2 e4 c# c# p, P# J0 e- \' p
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();) ^* s/ g, w5 S, L2 u- l
  35.                             if($active > 0){
    % w$ X: T( D+ I
  36.                                 //开启事务& w+ {0 W: {) E- u
  37.                                 M()->execute('start transaction');$ L1 s5 ]. X, z7 R4 H( l# r1 }( {
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));7 u# N; P5 o5 j; U" X) x: X
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    " ^7 b- D3 I' F% d: ^
  40.                                 $members_preferential    =    M('members_preferential');7 s% }! J" g1 `! h* R* c3 s
  41.                                 //对应投资金额,6 q3 Q3 u. Z( f8 F4 Z/ H
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    / R/ j3 [" w: y: h, F( t- o
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    ! L) h+ c8 o" a
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    % _. \. ^6 r6 q5 l4 L. I+ W
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券) G: l6 _' q9 u' Z; F5 v/ K
  46.                                 if($save && $add && $add2){: \+ V4 P* [' y5 r2 D
  47.                                     //事务提交
    $ a' z9 n) a# J1 [8 s
  48.                                     M()->execute('commit');5 S. V/ o* K; I( L2 E' O
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    , X8 K' W: d$ i) W
  50.                                 }else{
    # t2 ^" Q; {+ v# K! a
  51.                                     //回滚
    7 e5 j/ _6 z/ F5 M& s- r5 B1 B
  52.                                     M()->execute('rollback');& I8 w8 B+ ?  d/ E+ t. L9 s* k6 G9 |
  53.                                     $data['msg']='未知错误!';
    - H2 E7 K& G$ _0 H& s  I
  54.                                 }+ @; g% s! h9 v  |2 N1 x$ M
  55.                             }else{* n* S& x2 n, E
  56.                                 $data['msg']='红包已领完,你来晚了!';
    4 B8 ~. E$ Z$ ?
  57.                             }
    ) S/ A  y  r- X
  58.                             M()->execute('UNLOCK TABLES');
    7 |& z, C4 e# n4 K  {+ z2 ^- b
  59.                         }
    5 d9 H( ?7 [* }' O
  60.                     }
    ( K" _% V* ?3 v5 p9 f* h3 T
  61.                 }else{
    9 j  n* B" ~- f) L: V* I
  62.                     $data['msg']='非法操作!';( X7 b: Z, H0 N) k" m  _
  63.                 }, X  r( _' q6 m+ M1 Y, o  x3 @
  64.             }else{3 V& @& T1 e& I  h4 ]5 u
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';5 b3 `! ?5 p% n/ s
  66.             }) M9 D4 j2 a  M7 P: [
  67.         }1 l* u6 m7 l% j1 [: |7 C
  68.         exit(json_encode($data));7 j% g2 A6 p/ |- ]: I" \* C
  69.     }
复制代码
% K/ W! H! `) \: s. Q6 n

, M6 f9 {' j2 `0 A8 J
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 00:39 , Processed in 0.148114 second(s), 19 queries .

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