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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

+ w* X2 t( W+ C0 u
Mysql中的锁语法:! I  q: M6 p) @- Q* ^4 w$ B
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】" G- B0 o% m! X/ e. ?
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表; E; l2 y/ v$ E$ F5 C6 C% ^
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
+ u( @! \% ?8 P注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :: g6 \  n; W1 c5 m( O1 G$ S5 W7 |
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
) a5 N/ r: P% x% C; E7 E测试时,有个文件就行,叫什么名无所谓
总结:$ F5 V- e- T: K" S9 h  |9 x
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:: t) O5 D& Y* Y5 \4 m  c
1. 高并发下单时,减库存量时要加锁8 H& U* i& i2 x/ G8 i( X! ^% z
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    9 n. U" q/ G# [; y* N* A
  2.     模拟秒杀活动-- 商品100件
    6 q" S/ U4 Z. q, ?7 N/ o! J
  3.     CREATE TABLE ta
      g3 H, n# |( y+ L5 e  I
  4.     (
    9 e( a6 P. @  Q  l" e# x9 w
  5.         id int comment '模拟100件活动商品的数量'
    4 Q! Q) |2 C. y; Z3 L+ H
  6.     );/ `* ^8 r" W! O: u7 E5 k$ ?. X
  7.     INSERT INTO ta VALUES(100);
    / q9 `8 T' n- ]# z. l* W# k! J
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件; G, ?* C9 g: d; o7 b: z
  9.      */
    * f  g. r! m( i$ J) ^
  10.    
    , V6 Q5 y. C# |7 ], ]* d7 V
  11.     // 关闭错误报告
    % D& P3 D8 {0 B5 b4 l- h& i9 a2 o
  12.      error_reporting(0); & ?6 H: W  r! G$ F$ h/ E
  13. * G4 a" p2 W  h0 _2 Z: m, Q
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址7 {" |/ H3 v5 S8 u
  15.     $dbuser = 'root';            // mysql用户名1 z& I0 K8 z5 J; `$ L) v
  16.     $dbpass = 'root';          // mysql用户名密码2 t9 U1 u% r6 M3 f. M! s; e
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
      b9 u# i" `2 x, J( r- o& E
  18.     if(! $conn )" Z3 J! R; F& I( A
  19.     {
    # u  g; m7 e, H$ E
  20.         die('连接失败: ' . mysqli_error($conn));
    1 v- Z" L& k9 w5 n- r! G
  21.     }
    ; M5 Q" H) P& @: G" D* o% ^
  22.     // 设置编码,防止中文乱码
    # c+ G+ k' Y9 {* m: T
  23.     mysqli_query($conn , "set names utf8");; ?+ p; J1 x7 P. z/ v
  24.     mysqli_select_db( $conn, 'temp' );
    1 C# f# Z- s1 I) Y0 u- W

  25. 4 k7 U$ _2 E: e
  26.     # mysql 锁
    ; [+ H# R  j7 J* r
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 3 [& q  N4 A( j* _& c1 S$ z! s' @  P
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    " ?5 c- y  v" Q" G; x5 s
  29.     $id = mysqli_result($rs, 0, 0);
    0 n/ f# F  H! g6 K. E
  30.     if($id > 0)
    , h( \  l0 K) U; E
  31.     {
    & [9 b* x( q8 C4 r7 g
  32.         --$id;
    1 C: N5 D: W) j, z; B. C
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 0 J7 ^; H$ Q) z  s& h
  34.     }
    $ P5 J" ~) e5 H5 O* n" {

  35. - F3 ?" I4 W6 H- ]0 G
  36.     # mysql 解锁
    4 k  C6 h. F' @# P. Z5 Z4 ^7 L
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    6 X, g0 S+ E7 x
  38.     //查询解锁后的id值
    9 k3 z  _8 b/ V* ^
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    # o* s% @/ y, }# c( ]
  40.     // while($row = mysqli_fetch_assoc($res))2 u0 a3 G. y% a2 h8 I- r& k; W
  41.     // {
    2 _$ J6 S, ]& |. u) ^
  42.     //     $id = $row['id'];
    $ A9 L  E, W0 Q  a9 ?3 ]: B- n
  43.     // }0 P% q" u/ y% E, R' N3 C( _
  44.     // echo $id;
复制代码
: ]3 Y. Y, b& u& K. t, U

* N, J$ h) p! D  I/ [

) r% r0 p" Z+ P" g. @( U
PHP文件锁示例:
  1. /*
    ! U- x2 o7 Y: ]# K  i. l4 L
  2.     模拟秒杀活动-- 商品100件2 u" n3 a. h* Q. x7 J
  3.     CREATE TABLE ta
    2 h! A1 `. V$ y. C! f* @, I
  4.     (
    & N9 }$ l: |& {$ I  B8 h  M* a. x
  5.         id int comment '模拟100件活动商品的数量'  l/ p! J7 R$ g3 w
  6.     );
    1 d" H; c/ O, N" |: y" K$ a
  7.     INSERT INTO ta VALUES(100);
    4 @  g# _2 n  D/ \/ \( A: v
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件% n3 }) G+ e  V; W* z7 f
  9.      */
    4 u. [/ U, g! }, q, G) `& |, \
  10.     . m* t+ c5 w  O" ?6 o
  11.     // 关闭错误报告
    ! z. Z* _2 k( I3 z3 p! ~8 a+ U
  12.      error_reporting(0);
    ' M0 o4 s  T5 j9 W
  13. 1 t% r/ X1 w+ g) {5 B
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    & u- H( m, l9 w  b) _9 M2 I) d/ f
  15.     $dbuser = 'root';            // mysql用户名
    : o% o8 }: N6 P. x+ t* ]
  16.     $dbpass = 'root';          // mysql用户名密码: y2 e! t. F1 q+ s+ H* \
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    . G3 c- J6 X0 A, R* u
  18.     if(! $conn )' l5 A, @4 @( h3 {4 C: `+ l0 U/ G
  19.     {
    : [% C1 M4 [# N; E
  20.         die('连接失败: ' . mysqli_error($conn));# m- h. w, Z% w7 s
  21.     }
    : _* r: a" g1 Q7 W; v- D
  22.     // 设置编码,防止中文乱码+ X" h3 w6 V9 I5 F0 C1 o+ Z" a
  23.     mysqli_query($conn , "set names utf8");
    & P' G) D. R: l/ B7 E7 S6 T
  24.     mysqli_select_db( $conn, 'temp' ); $ G1 ?  _! Z* P; A3 T- [; a( m2 n
  25. # Z3 u; z9 ?5 \( u5 ?
  26.     # php中的文件锁 7 v8 @; W9 u- H/ @
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    , v' |6 H. a% U& L& q/ }
  28.     flock($fp, LOCK_EX);// 排他锁
    3 [( q5 J7 I5 j) N0 F6 |- o) S

  29. / |  Y6 ^, O- M
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 3 ?  S* }+ v$ \3 E2 O, l8 s# O: \' f
  31.     while($row = mysqli_fetch_assoc($retval))
      t* \: Q: r+ ?$ g
  32.     {
    ! l6 D1 X! @: D3 L  K$ Y
  33.         $id =  $row['id'];
    0 C2 s: i( |7 i+ {& P! \( w5 ^( L
  34.     }  t) k; l3 `1 B1 A& E
  35.    
    0 W8 o( v+ L2 t% C8 y  P
  36.     if($id > 0)
    ) Z" ]) m& K9 X1 G( n1 V7 w! x
  37.     { ; j' b* E8 L8 o) e. c2 A
  38.         --$id;
    3 C5 L+ t- q5 Q1 l( K7 p
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    5 m5 h$ |6 w$ C2 w# `$ y! i6 v4 L
  40.     }
    3 ~2 @1 y1 @$ J6 m. W. \. {! i; s
  41.     # php的文件锁,释放锁 : ~$ J7 G! D: Q9 Y4 E
  42.     flock($fp, LOCK_UN);
    : O1 X2 e, w1 w% O3 o4 `' p# U
  43.     fclose($fp);
    / r0 T8 n; n) i

  44. % B, v( _3 a3 p# o0 C. J
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');/ c- K4 V7 ~4 h0 M3 ^) p( a
  46.     // while($row = mysqli_fetch_assoc($res))4 O' K! x; [2 X2 w% t* z8 i
  47.     // {
    9 n& E9 t9 K. t% z: n! }  B
  48.     //     $id = $row['id'];
    ' P8 @7 h7 G+ z2 y. S
  49.     // }8 H1 X1 u# |0 C( {3 B4 _- Z
  50.     // echo $id;
复制代码
- j( j8 w. _4 q
' L; _% g% E( o6 z( W& J
抢券活动实例:
  1. public function envelopeSnatching(){
    " }1 M& }% b/ c* ~
  2.         $lingqu = $_POST['type'];
    ! i3 Z+ H( e: M- m
  3.         $uid=session('u_id');//用户id" |- A' t8 ~, @
  4.         if(!$uid){
    5 A# r7 p2 l9 c
  5.             $data['msg']='您没登录,请先登录!';0 x( a. D& a: s6 T  I
  6.         }else if(date('Y-m-d') != '2017-12-12'){, h. D' D. a1 }5 k# G9 X
  7.             $data['msg']='不在活动时间内!';
    + k9 t  ]9 W6 |/ K+ R$ Y; {
  8.         }else{  ^' B0 O0 R2 p8 i+ Q% M9 a
  9.             $hours=date('H');//当前小时数& x( q0 I% c0 ?% r2 L( ?, t6 r
  10.             if($hours > '09' || $hours > '17'){
    ) H- j0 D3 W6 b& c) I0 k% f
  11. # o1 U4 u; _: k7 F
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    3 @- u. ^( `1 C! F0 ~
  13.                     if($lingqu == 1){
    % k6 b' @. F4 H& `
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过3 ~; n- H* c1 E- H/ t
  15.                         if($hours > '09'){
    ; u3 n$ ~& [1 D6 z
  16.                             $num=mt_rand(25,28);//优惠券金额
    8 {/ ]' t* A$ Q0 E  W. y
  17.                             $id=1;
    2 `* h- ?- u! e  s$ s2 A
  18.                         }
    - P& }* F6 J. F; E+ D; `
  19.                     }else if($lingqu == 2){
      ?3 S2 ]+ a0 P
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    0 S$ D/ o8 P& T
  21.                         if($hours > '17'){9 @3 m6 D: v0 c9 {- m
  22.                             $num=mt_rand(50,55);//优惠券金额
    ' Q1 \( |  K! Z" w8 V
  23.                             $id=2;
    8 r" W* U8 f, H2 k. |8 I
  24.                         }
    " i! @* V0 @. |) H
  25.                     }- V) U1 _1 O5 W& i
  26.                     if(!$id){
    4 |8 g1 l% U& y. [
  27.                         $data['msg']='时间还没到,晚点再来吧。';; [  Y1 y* V$ _1 ]# \% I
  28.                     }else{5 l. n- ^: Q/ o% u+ R' E5 d
  29.                         if($is_lingqu){
    7 J' s( U3 n! C8 O) ]0 ^
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    ) p9 `" @! z& |5 }9 }1 z8 t
  31.                         }else{
    $ H: t2 \. O. g  D% q: Q8 S( t& ]
  32.                             //锁表
    % S8 v+ U9 a: Z' l2 z
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    : p6 \' M+ s! E1 D1 ^
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    1 H" o3 j% P  a* s
  35.                             if($active > 0){
    3 M% k- ]2 ~. |& f! L/ K9 M
  36.                                 //开启事务, e2 a: [2 p+ y* Y3 p
  37.                                 M()->execute('start transaction');# D: f) F- n, {
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));7 I# z, k( }$ V; B
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    4 _: F. T$ Z4 i6 x8 ?
  40.                                 $members_preferential    =    M('members_preferential');# t7 _$ v& l2 Z! N! C! U
  41.                                 //对应投资金额,7 m$ V4 }1 C, L( X9 E) e. Z
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    8 p: m3 w% D, Z4 Q& \' c9 f' N) _
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
      M/ \# k+ f+ J0 l( [  W1 I$ O
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间5 }5 S5 ^9 _% l) S* V& F9 ~
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    / O) n; V7 L1 L, W2 D: j
  46.                                 if($save && $add && $add2){
    % h; [$ G# ^! W4 `; v
  47.                                     //事务提交) Y  F! u% J) H- U
  48.                                     M()->execute('commit');
    , U2 w5 \; |: o" _1 _4 j/ h1 P) G
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';8 G  K/ _- H7 I
  50.                                 }else{6 {2 @( L# }' G8 p% l
  51.                                     //回滚) J) G( h$ U4 f& g6 s
  52.                                     M()->execute('rollback');( M4 B3 D! J3 x8 l1 R$ r, ]- S& {
  53.                                     $data['msg']='未知错误!';
    9 X' F. Y! p3 P  x( {
  54.                                 }1 D! F, B4 ~" E# O/ k
  55.                             }else{  |) U2 U4 h+ K
  56.                                 $data['msg']='红包已领完,你来晚了!';. d7 ?2 e, |$ Q, w6 z
  57.                             }* N! Y' j4 O/ I$ p! e3 G7 L4 K
  58.                             M()->execute('UNLOCK TABLES');* F! c5 Z! {3 i! a. C( ]
  59.                         }" p8 i  C- t; I5 U# `* a1 H, J
  60.                     }5 L: Y! D! X2 I4 [0 s9 w
  61.                 }else{
    * S: o. C9 V+ @" I3 R2 L) k. k
  62.                     $data['msg']='非法操作!';
    % G/ v' I% z* E. g
  63.                 }
    - V# f6 n/ H/ e" o- C4 H
  64.             }else{9 N- S- Y* Y+ Y; ]' k0 L" j+ e/ N+ D
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';/ v' g/ i" N2 L3 U4 H; s& g
  66.             }; F; W/ _! Y3 N; C: f0 i: L
  67.         }6 \' J( X0 M# T9 T$ M
  68.         exit(json_encode($data));
    ; b) o. E6 N& q+ L+ \: r
  69.     }
复制代码

, A/ ~  \7 t1 T4 m3 ^5 H" o5 t7 p# ]" [
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 21:11 , Processed in 0.056308 second(s), 20 queries .

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