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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

2 C$ k2 @5 h5 w& t( ?
Mysql中的锁语法:2 |; t- @% g6 L' I! z' _- Q+ W7 Q8 D
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
1 h: H# Y% \* S  d2 t& T# T/ |UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表( h3 T& L2 Z3 d; Q% t
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞2 g2 U& n9 X. H$ }' ?. T( X! p, k
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
, E, e( {5 c2 S文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
3 I+ K7 t' E' T2 `: Z! R5 x测试时,有个文件就行,叫什么名无所谓
总结:
' A+ |+ W0 @8 @  ~6 P; k* [项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
9 e6 a- B; y9 z$ `# X' k, }1. 高并发下单时,减库存量时要加锁
. ]! T0 A! Y* R7 d8 J1 {2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    . o) r* f5 l7 H) h8 Y/ S
  2.     模拟秒杀活动-- 商品100件
    8 w3 V6 S$ d/ v" a: n4 j, M
  3.     CREATE TABLE ta- h4 j, _  s& ~8 W
  4.     (
    ; z& X9 j+ y8 @  H
  5.         id int comment '模拟100件活动商品的数量'4 K" T0 V+ M% t) I7 J" m
  6.     );# A" j% R; `4 A, M: _: C
  7.     INSERT INTO ta VALUES(100);
    # U5 p2 i: x3 S: k
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件3 `) b$ w. Y0 u3 F
  9.      */ 1 k/ v* c9 K% B& P# W4 P
  10.    
    " j. c/ U9 N4 N. G" K; C
  11.     // 关闭错误报告; g  ~* h; M# H# [& ]
  12.      error_reporting(0); 2 R! P& T5 q; v! B! m
  13. ( l0 p  g. Z; n( L5 J. g) @
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址. G+ m2 O8 |$ D7 Y9 d& v
  15.     $dbuser = 'root';            // mysql用户名$ t) b* H! Y4 {: K2 R6 Q
  16.     $dbpass = 'root';          // mysql用户名密码
    , @" z$ k7 s6 U, \, v  Z! S
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    2 p5 I( g* y7 Q: h9 K' v
  18.     if(! $conn )3 o& `9 u$ ?$ ]. [( r( l
  19.     {# `8 @: G, i' n
  20.         die('连接失败: ' . mysqli_error($conn));
    & o/ U$ R8 O1 ]( o2 m3 f
  21.     }3 N1 [1 Y+ b% h, W
  22.     // 设置编码,防止中文乱码0 e3 c- s7 Y$ Z) q- c- L
  23.     mysqli_query($conn , "set names utf8");% Q* ~- R% ?9 k5 u# e% o" V8 f4 P  \  a; F
  24.     mysqli_select_db( $conn, 'temp' ); ! A5 m' U, F6 G" p9 Y% W

  25. # `! q* e( D: a0 V( s8 P: G7 E( \4 }
  26.     # mysql 锁
    ) Q5 q4 R2 ?/ m3 f
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 % N3 ^9 _$ e, `! ^- N
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    1 D9 Q# }' W  S  [7 a  T3 v* |
  29.     $id = mysqli_result($rs, 0, 0);
    / y* ]- A) P. E, }
  30.     if($id > 0) 6 ~1 H3 j2 q! i. \, x0 B
  31.     {
    2 V# Q, Y" v. M* l$ K
  32.         --$id;
    & Y. u) l3 |  Y, s- Y7 {" C
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 0 Q/ H2 A& K, ?( Z  z# D
  34.     } 9 @& O5 {( d) ~5 e
  35. % ?$ q6 s- X. @' h! Y4 A$ e4 O' G$ E
  36.     # mysql 解锁
    . E) S4 I0 U: P1 A! c
  37.     mysqli_query($conn , 'UNLOCK TABLES');" j) b, z. w+ I
  38.     //查询解锁后的id值
    % ?4 H8 [6 l; w* ?! Y# n; d% y- z
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    " `) E1 ]: t' G# ^8 F9 y% |
  40.     // while($row = mysqli_fetch_assoc($res))7 H8 @* K: G" E& v
  41.     // {7 x3 i. v- v. K
  42.     //     $id = $row['id'];3 `: n# n( N( \5 u
  43.     // }
    - S; |1 a. _4 i! k
  44.     // echo $id;
复制代码

2 ?" Q8 o! n5 r8 k* a7 E8 H+ x# ~/ m, r  }. r9 M5 K

4 n0 I7 n4 Z- d8 z
PHP文件锁示例:
  1. /*, g- p8 d/ G* h  U  s. ~& D7 m
  2.     模拟秒杀活动-- 商品100件" g- Q  Q2 c0 R( A
  3.     CREATE TABLE ta
    8 L  u- n& n( K3 E8 C$ W6 _) F
  4.     (
    & c$ e% E1 ]; H
  5.         id int comment '模拟100件活动商品的数量'
    ; t/ D: |, C  `; y. D7 [
  6.     );( v4 d* S0 s( W  g3 M' C3 @
  7.     INSERT INTO ta VALUES(100);9 @, m$ O# h, M3 H. E- i8 U* R5 X
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件/ p5 C/ t: C' X; @6 G+ Z
  9.      */ ' h; S6 r0 v$ M& n. e& r
  10.    
    , |$ C' Q" _! c2 Y( i9 K
  11.     // 关闭错误报告/ a1 a$ R! _* H, R3 q( t) N* d# R4 W
  12.      error_reporting(0); + x! r  U8 f! ~6 }' o. j# \

  13. 3 Z  o. w$ t; n! ~5 P
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址+ {! ^+ w- g4 k# }' Y
  15.     $dbuser = 'root';            // mysql用户名
    ( M& Z" V' E1 y1 e" U5 V! G
  16.     $dbpass = 'root';          // mysql用户名密码
    ' Q, E9 F& q3 f- G' o: l
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);! p8 [# t9 S4 F# V
  18.     if(! $conn )
    6 C9 e% Z6 w% y
  19.     {& A1 |) x- n( a! n- W$ T$ k
  20.         die('连接失败: ' . mysqli_error($conn));$ p/ a  Y3 i# q; @; N. W0 d6 x) S
  21.     }& u8 @% a; o( n2 P/ \5 [
  22.     // 设置编码,防止中文乱码
    ( i8 M% m% a' q0 p% y. d
  23.     mysqli_query($conn , "set names utf8");
    6 A# ?* t# c* @! x7 r. h! D
  24.     mysqli_select_db( $conn, 'temp' );
    $ e& d; l( _, o+ {1 N/ j' i6 \

  25. $ z( }; ]$ D6 T  x* l
  26.     # php中的文件锁
    ( A; |; p. Y; n2 \' P
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 % Y+ z* {5 Z+ Q4 T: A) L
  28.     flock($fp, LOCK_EX);// 排他锁   ?( N1 Q+ ^0 _% h% l
  29. " i) X* T/ X2 Z/ s7 v+ J
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 2 X! u9 @# d; N5 y8 J, O
  31.     while($row = mysqli_fetch_assoc($retval))$ G' J6 O6 {% o2 T/ \4 t
  32.     {
    % v8 Y: @3 y; n. n
  33.         $id =  $row['id'];% \0 Y" g1 d. `, r, u$ d( m+ X
  34.     }
    # D& N  {% [. _  Y' b" [: Q
  35.     ) I1 ~' k" N" y; i+ G
  36.     if($id > 0)
    . J9 v9 y4 n$ R* O6 k9 l1 G' P
  37.     {
    7 k3 ]: }- |7 x6 I$ R
  38.         --$id; & U4 o2 {3 W/ R" t% G
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    & [* F9 U( s7 Y7 k$ [
  40.     } , e0 o, w1 J( W
  41.     # php的文件锁,释放锁 0 n' K; {: H. W+ g! n* {  f
  42.     flock($fp, LOCK_UN); % z  W: K: \! V, b. a
  43.     fclose($fp);
    6 Z, h7 U# \, z8 Q# R- U+ ?

  44.   z% V" s% M3 ?$ N3 ]
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');+ s0 O! B6 V% E1 J7 H- ?. t
  46.     // while($row = mysqli_fetch_assoc($res))
    $ A( I# [$ Q' p7 h( ]
  47.     // {
    & P0 ?; v* `5 V& V: [
  48.     //     $id = $row['id'];& I# I. |- Z" ]5 u' E& P
  49.     // }
    4 C( v7 s4 i' ^  Y. q
  50.     // echo $id;
复制代码

7 p/ B# y; n, I* G: A0 y7 [6 Y( R
8 Q8 w9 ^. G1 m. C" K+ I7 m
抢券活动实例:
  1. public function envelopeSnatching(){
    2 N  y% Y% ?" F5 D
  2.         $lingqu = $_POST['type'];; a6 r: ?3 E1 P" j. w
  3.         $uid=session('u_id');//用户id1 I' Y; [1 ~6 R* t( S
  4.         if(!$uid){
    ( S/ V: M% t$ u) T6 d5 y$ X
  5.             $data['msg']='您没登录,请先登录!';5 d$ `+ Z8 W* y5 ]+ V
  6.         }else if(date('Y-m-d') != '2017-12-12'){  V- b! Z7 C/ h9 f
  7.             $data['msg']='不在活动时间内!';2 e5 J* j* d- M1 ^( K0 o9 i
  8.         }else{
    ! \6 J* A( F/ c# `/ K
  9.             $hours=date('H');//当前小时数
    7 t8 r+ R6 l3 o* r& X9 ~  F
  10.             if($hours > '09' || $hours > '17'){
    2 t. _. @  Q; a3 w+ Q
  11. ! {& b* `$ B: x3 h. o/ p
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    # ~; U; [4 \, r5 n# q& ]
  13.                     if($lingqu == 1){
    / H( _9 ]' g/ |' D' q. |4 G
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    / p5 M! u( ?: @) k( ?8 Y' ?3 D
  15.                         if($hours > '09'){" J- w$ A0 i& }! G; W: W
  16.                             $num=mt_rand(25,28);//优惠券金额( _) p2 C- n. I3 k, i1 c
  17.                             $id=1;
    5 B0 J9 k3 C4 t& Q+ ?1 o3 ~3 X
  18.                         }$ z' P; F! G3 z
  19.                     }else if($lingqu == 2){
    , \; m) K6 X, @) d
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    1 {2 g1 v3 @9 u% I3 n: k! N  r
  21.                         if($hours > '17'){
    7 o. i& v) s- O- C: u% I9 r
  22.                             $num=mt_rand(50,55);//优惠券金额
    , ]- L) Q) A" O4 g/ f, }& D$ x
  23.                             $id=2;9 V0 C/ s; B2 c8 q3 W$ B# |  m% ?9 N
  24.                         }+ ^2 `$ L: L$ l9 p& j  g+ c
  25.                     }2 V/ n9 f# K' T! j, n' L
  26.                     if(!$id){( a' |3 n4 K/ j, U  n; F
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    5 m! O6 v  L4 N+ q, V' i- ^
  28.                     }else{
    ; t  @4 H3 K/ d9 Y! G9 O8 h# V( x
  29.                         if($is_lingqu){
    - ]% b2 x5 x2 ?1 v7 N
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    % \* q6 U6 P' \$ h
  31.                         }else{, d  e' Y1 o0 R7 ~
  32.                             //锁表
    1 c9 H6 V/ I* p% h5 ^- O
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    ' U! |  }" [4 c) I) k8 ^
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();7 s* d) X6 m( x; d9 ]( h5 X. t# K
  35.                             if($active > 0){  `; q; W: s  M7 p
  36.                                 //开启事务4 s' ?3 H9 d$ n9 \7 a
  37.                                 M()->execute('start transaction');
    3 `4 {" @  H' ?) s/ u4 z6 v' ^
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    $ e1 Y, x9 p+ }. y- L1 o
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
      w7 c7 ^3 s% y/ }3 v) x
  40.                                 $members_preferential    =    M('members_preferential');7 O' B: C* F0 A, y) k! O
  41.                                 //对应投资金额,
      u, e1 K0 `, j8 @$ e9 D  H
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));3 @5 M& R5 S; ^, f( S/ m1 g
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    # z. k6 Y$ z! J9 T* O" I; P$ ~
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    4 o: x# u- d1 [& V% [1 O
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    # X! n' I# O3 J6 R
  46.                                 if($save && $add && $add2){
    # @& n; m6 T- m, X
  47.                                     //事务提交
    ' M; s$ o6 ^9 O- |5 Y- G' Z
  48.                                     M()->execute('commit');
    , V6 ?2 j! m. `  E( F9 r
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';7 n6 `, M: b: P9 L9 }* R0 n
  50.                                 }else{) `) E3 `4 q3 b1 O! p( n
  51.                                     //回滚
    0 L! e8 ?( l5 U
  52.                                     M()->execute('rollback');; P% Q$ C7 o5 n' a( S/ v) a
  53.                                     $data['msg']='未知错误!';
    ! Y2 u" B! V' h
  54.                                 }  e; r& l9 T: Z7 u1 z& F
  55.                             }else{
    9 J2 q$ |: w- P  R0 T& s4 d% `, }  O
  56.                                 $data['msg']='红包已领完,你来晚了!';/ _  F6 T: L7 M5 g
  57.                             }/ W, K, a# \, h# i- Q& V; w" w
  58.                             M()->execute('UNLOCK TABLES');1 X; |7 Q2 D2 K% k7 L: L- y
  59.                         }
    : h  T9 ]% s! t% E2 {+ I7 Y: _
  60.                     }! K2 U& c5 f; ~* U
  61.                 }else{
    8 ]3 J  a/ W4 h7 f6 A- O
  62.                     $data['msg']='非法操作!';
    * ]1 @/ A# W6 d8 K- H2 e
  63.                 }. x8 {7 m$ @" m9 A
  64.             }else{7 h7 M' e; F! g  ^- E/ {
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';2 {! ]* T& S3 W  l1 l
  66.             }
    5 K: j) p/ m  n' ?4 W1 D  b
  67.         }
    9 v" Z& ]3 @! V5 S
  68.         exit(json_encode($data));8 S9 r1 D# n' k" F4 u6 U
  69.     }
复制代码

8 Q$ k$ S" r0 Q6 `$ q& w" E" X) Z% c0 D  z$ D! G
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 23:59 , Processed in 0.066252 second(s), 20 queries .

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