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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

/ U' D3 }1 h' R' `( ?% D
Mysql中的锁语法:4 \& R/ u- N6 Q! ]: o+ T
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】& X% V  X- M* Y- y, X: j& E9 b
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
% A. M/ R& R, o, SWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
% |8 ]. K: n' S% T注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
# A) j7 j& X  l  L文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
) c' y8 Y: [$ r7 `) `$ N  D测试时,有个文件就行,叫什么名无所谓
总结:: g6 g( W0 D2 x! ^' n  u- F
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
5 o& M1 `% i7 M2 r6 M1 ]1. 高并发下单时,减库存量时要加锁
; B9 C' ^) Z. |- ^' y2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    ! K" d9 b) n) V! W, K& V- F- J
  2.     模拟秒杀活动-- 商品100件/ N( [) {6 B/ G# W9 D: U
  3.     CREATE TABLE ta
    0 ~' z+ ~6 Y4 q" J3 m
  4.     (
    3 P. Y4 V$ x- O: r9 x- s
  5.         id int comment '模拟100件活动商品的数量'
    ( Z* t: H2 E8 d4 j) U" D5 R4 y
  6.     );
    & g5 s& Q% Y( V3 Y, v6 x# n% R
  7.     INSERT INTO ta VALUES(100);' C# y, X6 u9 L
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件+ l( y( I5 d2 B: w0 }4 `
  9.      */
    + T8 r, b5 X5 B# R( c" P
  10.    
    - A1 P! f& {) R* z: [
  11.     // 关闭错误报告
    8 M$ v" z. {$ {3 o, F
  12.      error_reporting(0);
      ^! w. h9 ^5 w# Y9 V
  13. + I* p6 f$ M, f* W4 `5 P
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    - K  C+ G) q, G& _4 {4 C- a
  15.     $dbuser = 'root';            // mysql用户名5 d1 Y; y+ t0 T, `5 v  J( j
  16.     $dbpass = 'root';          // mysql用户名密码* i3 @1 C; o, F( o8 Z& x
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    0 ?) C- v+ b0 c. Y% r) O5 T9 Z  k# o
  18.     if(! $conn )
    / L3 v, R2 V8 }
  19.     {
    / F0 J, \1 R) ?2 {
  20.         die('连接失败: ' . mysqli_error($conn));
    . _' w$ ^- q) C3 _" B  b* c* h
  21.     }& x9 ]" B! K+ g0 e
  22.     // 设置编码,防止中文乱码% Z/ G0 ~' t0 T5 }5 `4 s! C  U
  23.     mysqli_query($conn , "set names utf8");  v; M# V- ^( v% O( C
  24.     mysqli_select_db( $conn, 'temp' );
    % \% u! x0 D8 }( ]
  25. ! K3 u+ k. U* y6 }! i$ u$ ]
  26.     # mysql 锁
    * U1 }  G- y# v5 a/ q" f
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    / P' Z5 F( X, _: G' ~- V
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    5 G+ o. B* l- J' b  P+ ^
  29.     $id = mysqli_result($rs, 0, 0); % W/ L2 `: s0 a) x3 `
  30.     if($id > 0) * v! Q0 R3 k- K
  31.     { # Z; Q# w. u8 S( u/ s  g: V" ?
  32.         --$id;
    0 P9 m) h1 E; O- z8 i3 u4 K0 D; u- @
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    - Q4 F5 j. I7 `- ?
  34.     }
    ( S/ I$ _  B3 }! y0 d

  35. 3 |1 n% E' Z. D# g% O, b! l7 _, _1 G
  36.     # mysql 解锁 # m6 {/ f/ n/ \: n+ L1 [, e8 h
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ; L/ I- ?# l, E; _- I# j4 M) P4 p  w
  38.     //查询解锁后的id值' G5 z/ h4 C, x1 N; J) R
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');2 w0 X+ D1 S3 p* P: G
  40.     // while($row = mysqli_fetch_assoc($res))1 C  y3 a. F0 ~
  41.     // {* z6 i5 K$ H' b) w) q6 i. [- ^
  42.     //     $id = $row['id'];
    / T+ @6 `8 ]9 E$ v1 n
  43.     // }- Q6 R0 v! r9 I+ n8 s3 w
  44.     // echo $id;
复制代码
: n& @4 L4 W! s7 J& o% m7 \" W
5 l3 r3 v+ U  C) R/ y3 t; }

+ j) x( U4 v2 }' ]/ I) \
PHP文件锁示例:
  1. /*
    / E- A6 f+ {. P8 {8 j: z1 I  c! z
  2.     模拟秒杀活动-- 商品100件
    ) G; d1 x0 L/ l: X! _; `$ s& f- f
  3.     CREATE TABLE ta+ r: h# j* O2 p2 @8 U
  4.     (7 S% A  {) ]. k! \  L4 [
  5.         id int comment '模拟100件活动商品的数量'5 {- K/ a7 J9 Z8 J
  6.     );  B. t6 w+ w) g3 g: w
  7.     INSERT INTO ta VALUES(100);& ^( u+ f& i1 {+ k- B' w. ^
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    - e3 C) K- y3 s9 ^& i3 W
  9.      */ : {4 Y, ]5 D& b% Z- w4 M1 \& v
  10.     $ Y) h) i  D( q7 e& I) I  _0 @& J
  11.     // 关闭错误报告$ `. Z( Z8 L% w$ W. k+ E' ?0 D/ y
  12.      error_reporting(0); , H: J" u& T; G: Z8 z+ }

  13. * S$ x. Q4 {* f) @& B
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址/ {; l% I: V! N, o! y1 H7 }
  15.     $dbuser = 'root';            // mysql用户名! X5 {7 a- c' A& j9 a
  16.     $dbpass = 'root';          // mysql用户名密码! g! ^# z8 S) }! @; K( n9 T& [' r
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);+ C, \) z" j4 m+ I
  18.     if(! $conn )
    ' o, D5 ~* r" K1 i. p% t. [; h
  19.     {
    ! i5 k$ }, G1 g5 D
  20.         die('连接失败: ' . mysqli_error($conn));) J" D' M4 a  Y; ~$ j
  21.     }
    ! Z9 h$ k" o$ Z* s+ E
  22.     // 设置编码,防止中文乱码
    - s. [! y& M: ~- k& H4 W
  23.     mysqli_query($conn , "set names utf8");
    4 o( e& I0 M, S+ `
  24.     mysqli_select_db( $conn, 'temp' );
    & d4 N3 ?6 h) N& x% V

  25. % c7 k: P) P5 L' U* q/ D: j
  26.     # php中的文件锁
    * \1 t& g- g3 G& u, K# t
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 $ E# p2 }9 ?+ u2 X
  28.     flock($fp, LOCK_EX);// 排他锁 ' g+ Y4 k( M4 K# N" n" f- i0 u

  29. # p/ L8 s8 v; w0 y. |
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    8 M' N  K! x. C# w- i/ \
  31.     while($row = mysqli_fetch_assoc($retval))
    ! m1 F, U; V8 l) J; s
  32.     {' S: V+ a# \; L% ~6 [: g
  33.         $id =  $row['id'];2 j9 R5 `. Y) R
  34.     }0 |- \& K- A- u6 Y7 p4 k+ N
  35.    
    5 ^6 r9 A" W4 ?8 U$ {/ [7 A# e
  36.     if($id > 0) , U/ d$ L9 q3 l. T; _2 s2 C: [* ]7 n
  37.     { 6 T9 J5 V& Y* ^. V
  38.         --$id;
    $ f9 t/ b- g3 G! _. r+ b
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 5 d3 j- P* s3 Q2 `* x5 n
  40.     }
    + L2 ?5 @% O1 E- Q
  41.     # php的文件锁,释放锁 ! S. o4 G0 F6 g$ Y0 t
  42.     flock($fp, LOCK_UN); & p5 c' o+ D+ Z& A, m
  43.     fclose($fp);
    / D  `/ a. g* {% B* m$ i0 A2 l
  44. / @* v' h- |0 K9 w; A
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');2 N0 J+ w4 O8 H9 L6 c; N
  46.     // while($row = mysqli_fetch_assoc($res))' r5 z: Y- o0 a% u+ O
  47.     // {
    ' V2 R4 V7 C' w
  48.     //     $id = $row['id'];9 U; X% g; V* l9 s) V! V' t
  49.     // }
    $ ~* @7 I$ o% p2 o& e2 k+ z7 i
  50.     // echo $id;
复制代码
( K: ~% e+ o5 O, x( Q
9 g% J; }) \( l3 X' |/ t! Y
抢券活动实例:
  1. public function envelopeSnatching(){
    7 o6 i( `+ y( x9 t! M- X3 a; K
  2.         $lingqu = $_POST['type'];
    8 x8 m/ ^& ~8 ~4 j7 N
  3.         $uid=session('u_id');//用户id# j7 N- W' t5 k& b& A
  4.         if(!$uid){
    4 o! c4 Q( _0 S1 l+ x. M" H! J
  5.             $data['msg']='您没登录,请先登录!';, {* u& I% S) g# I
  6.         }else if(date('Y-m-d') != '2017-12-12'){, l' _- _* m6 O
  7.             $data['msg']='不在活动时间内!';
    - l- U6 p/ ~# _+ B. f3 c+ M# t6 L+ x
  8.         }else{" u6 i! J6 Z; X
  9.             $hours=date('H');//当前小时数
    ' X% u' m' k4 W- Y% j0 W
  10.             if($hours > '09' || $hours > '17'){
    : P: [3 o9 h( y

  11. , m% e# ]1 A( I) P+ k# ?' Q7 Z
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    3 P! @3 p+ k8 l1 y! C
  13.                     if($lingqu == 1){
    * T& E/ t2 s; C+ q. _2 r* w% r
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过7 J8 j2 I) X% \: q/ f8 D/ y, @/ x. b
  15.                         if($hours > '09'){
    * p* }0 Y$ `' u/ O  f# a
  16.                             $num=mt_rand(25,28);//优惠券金额
    9 N  M% g  Q  d
  17.                             $id=1;) N4 n& ~- M( h8 X1 p
  18.                         }1 C( [- B# c- d6 U& b' S
  19.                     }else if($lingqu == 2){
    % P! T. G5 b% I$ q: J' z3 G
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();3 x) K- W9 c& i! z
  21.                         if($hours > '17'){* X. R& Y9 a7 M! J7 [/ _0 a4 r
  22.                             $num=mt_rand(50,55);//优惠券金额
    8 Z9 y4 _' Y! Z
  23.                             $id=2;& p6 b+ U, T& ]6 L6 L* U
  24.                         }
    4 n3 l: u# y2 r0 b* H- ~
  25.                     }
    1 A  h. Z0 |( D
  26.                     if(!$id){
    ( B  Q# F& {, \
  27.                         $data['msg']='时间还没到,晚点再来吧。';* E  G8 j$ X7 L" X8 r" j) l
  28.                     }else{
    * `0 b  P2 H2 t5 l8 t
  29.                         if($is_lingqu){- t0 v7 @) f( n- w" f
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    / w( M) I; H/ l0 b& n
  31.                         }else{
    $ G1 r7 J7 U( X: w  {7 z# n, V! c
  32.                             //锁表$ Y3 r: v/ ^6 `( W- K5 m6 v
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');/ Y  n1 d$ {; Q2 V: f/ Y+ h1 T
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();3 l2 G- {$ q. e! K1 A. s
  35.                             if($active > 0){" z! U2 `+ T6 b4 D6 t" b
  36.                                 //开启事务
    2 h$ V1 i1 z# l0 K
  37.                                 M()->execute('start transaction');: n1 w# n+ g/ c$ C3 j% c1 i+ r9 \
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    $ V6 _/ R6 {( o, o/ \2 ?: x
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    4 }5 u, t5 R+ d
  40.                                 $members_preferential    =    M('members_preferential');
    ' a6 @! h7 j& C! g' M9 i* T
  41.                                 //对应投资金额,
    # n1 K2 T4 M* @5 b8 Q' Z
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));$ o1 \: k/ e6 Y& L+ S" o; F
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    0 u: I- l+ g5 S6 K
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    : g4 F2 ~5 T' }+ \) H" b
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    % f& n2 ~% f. ^6 K
  46.                                 if($save && $add && $add2){
    % U6 z" z8 H1 v, X3 [3 _% ^
  47.                                     //事务提交; b/ D% W5 K! F, A( \5 A
  48.                                     M()->execute('commit');" o; \7 h3 a  X  m& D7 v
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';0 `! h2 u, w) ], J' m3 F
  50.                                 }else{
    ' n/ G! ]1 |" E4 x# o  k; r5 I% d
  51.                                     //回滚- n: X+ D$ P  y& {
  52.                                     M()->execute('rollback');/ g; w/ S+ s9 r2 |+ t, M( f
  53.                                     $data['msg']='未知错误!';
    / \+ R; ~/ ?& p
  54.                                 }2 B' z8 M' H( z' x2 R
  55.                             }else{
    , i" f" e+ r" H) L) _
  56.                                 $data['msg']='红包已领完,你来晚了!';
    + z$ l! I8 A/ `, s
  57.                             }, h" r0 U% M, k' K, e1 ~
  58.                             M()->execute('UNLOCK TABLES');- v) p' V7 |8 l
  59.                         }. ^1 ^8 @1 Z0 t
  60.                     }3 T/ X4 M( F, W9 e2 n
  61.                 }else{
    8 ~# q7 R3 o9 m, N9 D) `+ E
  62.                     $data['msg']='非法操作!';
    ! a% s: @" N2 i0 q
  63.                 }
    * Q( `4 K* P! B" q* |/ P- d* }
  64.             }else{
    0 E8 p, ~& M* N
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ) R4 F: V7 O2 C7 t
  66.             }
    - @2 z! J9 A3 T$ s4 I. j/ f, y
  67.         }
    6 |" z3 k8 L: Y* {+ v8 L/ d" t
  68.         exit(json_encode($data));. L$ n' f2 U6 X# l( t
  69.     }
复制代码

1 C- a% C9 u3 f+ R' x
6 D8 g; X- j' u6 [1 y' c" `
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-5-2 11:48 , Processed in 0.051402 second(s), 20 queries .

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