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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3877|回复: 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://请求的脚本
复制代码
, D: e7 Q* s1 J
Mysql中的锁语法:
: G) P7 Q! C1 q4 p# f' w" GLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】1 Y5 y" Q+ i' Z* Q5 O) h3 j- m
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表: ~- U6 Q: C3 A& K- I
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞1 r% d1 G" F) v. [
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :$ N; C6 m# [0 a$ t' s; q0 u
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
2 O0 F& M# H* ~6 n& Y" ~测试时,有个文件就行,叫什么名无所谓
总结:
+ S8 M6 }) a5 a3 h1 x) {项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
) p* e7 n- N& I' U0 ^1. 高并发下单时,减库存量时要加锁
) x& y  l5 l7 d. g; h" W9 h2 y2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
      q( M2 v4 `9 T4 B" U
  2.     模拟秒杀活动-- 商品100件5 F2 G! A1 f0 J7 D
  3.     CREATE TABLE ta# a! L/ \! O2 b7 Q7 L/ u9 @
  4.     (
    8 S8 i5 l  O- }3 x: C& N
  5.         id int comment '模拟100件活动商品的数量'. M. {/ ~, ?7 J9 Z6 w
  6.     );8 N: o& g2 i+ }" Z2 ~
  7.     INSERT INTO ta VALUES(100);8 c/ }' k! {  ?+ ^
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件# I; [% \' L, f! m$ Z( X8 }' v! a
  9.      */
    - d5 u# t! ?) K5 t; N+ n3 `
  10.    
    5 ]( x, @% l, @! Q! O
  11.     // 关闭错误报告3 M8 ]7 m9 o2 \3 _/ W9 P! e+ \8 b; ^
  12.      error_reporting(0); # H; C2 r6 ?* A. }& Z2 g/ v5 G

  13. 4 N1 p2 S" b! J! r
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( ^) ^+ q( X! d: k* Z- a' E8 j
  15.     $dbuser = 'root';            // mysql用户名# t1 N9 b- `/ a# U! o
  16.     $dbpass = 'root';          // mysql用户名密码5 y6 T( p6 M7 I6 F
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);3 l( I" ^' ?- X% j+ J3 x0 h
  18.     if(! $conn )
    & b) h0 l2 D( S0 P: z( H2 P# ?
  19.     {
    % b2 ~1 m) @! w2 K' l& E, D: Q+ u
  20.         die('连接失败: ' . mysqli_error($conn));( b! f1 P9 x" F# V; F% _4 P6 W
  21.     }
    , Z2 x; }$ |7 e! G* p0 ?
  22.     // 设置编码,防止中文乱码* m% G. _. g- L, L. l* i
  23.     mysqli_query($conn , "set names utf8");- Q3 z1 q# l3 T  S8 B' a
  24.     mysqli_select_db( $conn, 'temp' );
    * F$ {3 z, `( A& @" |# ~

  25. 0 O+ v( t: N7 H& X! M* I' p  c+ }+ N* G1 E
  26.     # mysql 锁
    0 _* d# Q; [/ R& V6 P- g, G  I+ F
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 2 H+ Z1 u* Z0 [4 v
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); ) R" z+ I2 N) H% o* C; k
  29.     $id = mysqli_result($rs, 0, 0); " w3 Y; u0 `0 J$ @
  30.     if($id > 0) ) V( P2 W+ t+ t2 b; d# B+ U; F
  31.     {
    + f: l: m0 I: U/ ~, k
  32.         --$id; , }0 `- Y8 o  P* C  F5 |9 Q# L
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    & `6 a' E) j# H% V
  34.     } ; |2 P4 u( c" r' u* d

  35. $ t4 h- c# d6 \$ F
  36.     # mysql 解锁 6 I9 @8 U' {5 A/ M: X$ S) l
  37.     mysqli_query($conn , 'UNLOCK TABLES');: q; d# Y; Y0 X6 C
  38.     //查询解锁后的id值
    2 z) z& [6 B6 F6 G
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');6 c& q  Y% S3 k/ A$ f. s6 P
  40.     // while($row = mysqli_fetch_assoc($res))
    1 `( M5 X2 w2 P
  41.     // {0 P' `1 @- R, ^& F
  42.     //     $id = $row['id'];
    & \) V" t% ]4 d
  43.     // }. y' M; `7 @# c
  44.     // echo $id;
复制代码
  Y0 ]& p) j/ ?: {2 Y3 O
# e) X* w) ?+ c5 }" }- [" N$ x

& n0 E  ]7 D5 y# j. S1 e
PHP文件锁示例:
  1. /*
    * r0 N' |+ v. A$ Z- ^
  2.     模拟秒杀活动-- 商品100件
    ( z4 \+ k) P8 i  l7 B8 V. A
  3.     CREATE TABLE ta
    ' z- [( i, G8 P& g7 n5 i. l& }" {
  4.     (; X4 l( H& F1 T. `2 p
  5.         id int comment '模拟100件活动商品的数量'
    ; h) w% ^' @: x& ^5 V2 |
  6.     );3 P3 q6 ~+ W3 m+ K. L
  7.     INSERT INTO ta VALUES(100);9 M3 f5 G5 X' q0 K9 R
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    " U( Z& E6 k7 m& b
  9.      */ 0 W8 b3 b5 Y- ?; `( I; y$ t8 R
  10.    
    7 \8 t  z& I& X% e( `& e- @
  11.     // 关闭错误报告
    ( B3 g, _6 ?8 x6 C4 Z5 ~
  12.      error_reporting(0); - ~3 q& F; C& c3 a. c& q5 p! X! Z
  13. 3 J3 L% \% A" y  j- w+ D' Y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    : v8 U: W) D2 g/ P$ L* G+ X# e1 ?
  15.     $dbuser = 'root';            // mysql用户名
    % W" v& Y0 J) p, }( A. S
  16.     $dbpass = 'root';          // mysql用户名密码4 M6 }8 J8 u( i% s
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);" m7 }) h. N- M* O6 v
  18.     if(! $conn )
    6 A7 D, j* T! H, I! o  Z+ e( c
  19.     {
      K, u' ~; U( L5 J, r
  20.         die('连接失败: ' . mysqli_error($conn));/ ?( D7 n. d- q2 ]
  21.     }6 W) o! \4 c" z) G; x) X; {' o8 O
  22.     // 设置编码,防止中文乱码
    / R: _7 [" [- i5 I
  23.     mysqli_query($conn , "set names utf8");7 ?; y$ q# L5 J1 f4 w0 U# m
  24.     mysqli_select_db( $conn, 'temp' ); ) P9 m2 ~' q/ m/ g6 D
  25. 6 |. U8 ^) {4 ^; p3 s
  26.     # php中的文件锁
    : J- ^' C) P: f% h4 K6 j
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 $ r- w3 U# @; X' |$ f6 w
  28.     flock($fp, LOCK_EX);// 排他锁
    ) _- J% \# Q. p3 U+ B# V/ S/ I

  29. 7 {9 f+ t1 R+ ~5 m! b
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    3 X  T/ ^. Y% U$ p
  31.     while($row = mysqli_fetch_assoc($retval))
    5 s/ ~; `. c/ L( R5 [5 `. t- I
  32.     {! E; h# H5 Z# t  `* D3 L) j
  33.         $id =  $row['id'];
    9 }+ {7 c3 j7 Z9 X# H
  34.     }
      L# |( _3 x+ ^* V% Z. M4 \0 ]
  35.    
    # g: ?9 P3 f6 f/ o
  36.     if($id > 0)
      r8 P# |8 m1 g
  37.     { 1 B' Y; c# w7 `1 V  ~
  38.         --$id;
    2 U2 r+ F1 M$ L8 F: N3 A" |$ V' x
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); # t" s. U6 p$ V' u- H  P" S
  40.     }
    3 o# u" g1 c& s2 ]' C
  41.     # php的文件锁,释放锁
    ' O* l# L2 C  V0 k* ]2 M8 M
  42.     flock($fp, LOCK_UN); ; {+ ]4 }, n' u& v
  43.     fclose($fp);
    & \. ^+ V6 b- z0 N6 V

  44. - q4 t1 j1 S- G  [  @3 ~! w9 G
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');1 x3 A3 B% C% L5 E
  46.     // while($row = mysqli_fetch_assoc($res)): l& `" W& _) C, j& h: Z5 p6 B
  47.     // {5 v! g. q/ a( \; D# `
  48.     //     $id = $row['id'];" p0 s1 E  F2 [) f9 O
  49.     // }; r. E4 j+ G# g+ }3 _  I
  50.     // echo $id;
复制代码
4 z% p5 t; C8 r- i' J4 s
* T2 _% s$ p  n5 {+ f% v
抢券活动实例:
  1. public function envelopeSnatching(){
    ! X/ K9 W& I2 [, n" k
  2.         $lingqu = $_POST['type'];2 M7 H. \# e( d# a" T
  3.         $uid=session('u_id');//用户id1 z' P8 j5 \5 q: r) G
  4.         if(!$uid){
    + K; ]; {: v5 N* I# Q
  5.             $data['msg']='您没登录,请先登录!';
    0 C* w6 g& g9 M3 i) _$ |1 [
  6.         }else if(date('Y-m-d') != '2017-12-12'){8 X. g5 E( x- j$ L! e0 O
  7.             $data['msg']='不在活动时间内!';
    % w0 E9 Z! P; W, S# F4 ~
  8.         }else{7 f% t( z6 t: r" h7 `0 B
  9.             $hours=date('H');//当前小时数) O4 \% {$ C, S7 g1 d  l+ H- }
  10.             if($hours > '09' || $hours > '17'){
    5 U/ `1 P# D) J2 R, v

  11. + M$ k7 E4 x4 H: n. ^
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的- T' L1 p. m0 S( {% \& f
  13.                     if($lingqu == 1){6 T: N5 j7 ]. E# d1 w
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    2 x+ N1 k/ M# e8 q9 z" X8 W
  15.                         if($hours > '09'){
    2 M/ g. ~  Z3 g, T3 v
  16.                             $num=mt_rand(25,28);//优惠券金额
    ' J8 l: B" s$ v+ j6 [
  17.                             $id=1;
    , b! |: G1 p3 u. _5 l7 P" T7 H
  18.                         }
    , m0 t% {- E7 u) U) P0 Q3 T
  19.                     }else if($lingqu == 2){
    7 p; ]9 K/ [" W
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    - j% r8 T2 s7 D" M$ q
  21.                         if($hours > '17'){
    8 e, A2 @; E# k- ?
  22.                             $num=mt_rand(50,55);//优惠券金额" P# G9 E( W) ^
  23.                             $id=2;' @0 m5 D4 M7 _8 \5 |2 J* w& v
  24.                         }
    + P" z( {4 j3 i( U9 ~7 c
  25.                     }
    5 v7 V. ?9 D; ]& S
  26.                     if(!$id){
    3 i  p6 M& d' w9 C0 G- ], t! U
  27.                         $data['msg']='时间还没到,晚点再来吧。';' p' m: D( g5 Z. _# E% `
  28.                     }else{
    ' D4 k1 t( ?  J- t1 i
  29.                         if($is_lingqu){
    : V7 D, d1 d( B- \: Z& {  {
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    & b: p/ {! }  }" j4 N9 s
  31.                         }else{% i7 X' `0 f5 c+ d( L7 f6 s
  32.                             //锁表
    ) `9 T) }9 f4 Z1 ]
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');4 Z  @3 L1 S2 u; v
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    7 G& A4 E; o0 e2 _
  35.                             if($active > 0){2 r. k; {" q: y1 T# j6 o( _
  36.                                 //开启事务
    # q/ e, R( T0 n& M# b6 u2 R) T
  37.                                 M()->execute('start transaction');
    & ~% C& e* o3 X2 b/ J
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    1 p: Q7 i+ U$ C9 `! l3 s
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    9 `* B6 }8 Y$ k" k& q
  40.                                 $members_preferential    =    M('members_preferential');0 q+ p0 g0 w/ N) a* d  H% s
  41.                                 //对应投资金额,5 s( \. _, P: ]8 r5 {
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    / j0 I7 \1 b+ G# \: X2 U
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');; _. F" H+ e! U) L8 t5 |
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间, m) }5 B; `5 q# e. m' d9 O- u3 N
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    1 S+ t, N1 ]- R$ ^( r
  46.                                 if($save && $add && $add2){0 c% B3 p9 u6 A9 n9 [! `
  47.                                     //事务提交1 g# y& ~1 j( I( w0 B. v
  48.                                     M()->execute('commit');
    ' b6 _$ f3 W0 x* N2 C6 f
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';7 w" U; J$ N# s0 s7 X: A# A6 U
  50.                                 }else{0 t9 I. z' u( r) v& n# v' ^' h
  51.                                     //回滚1 u  w9 M  V4 U
  52.                                     M()->execute('rollback');
    3 \# w$ d7 ^: ]% A" S
  53.                                     $data['msg']='未知错误!';
    & B: \2 R) |: s; h9 H8 z
  54.                                 }
    - p6 R3 N4 O, [9 m9 r2 C+ O
  55.                             }else{
      f8 B% i+ F6 g
  56.                                 $data['msg']='红包已领完,你来晚了!';
    % e" M. O3 n% I! V5 P, y; `, X
  57.                             }
    & a+ |) o2 X& n( z
  58.                             M()->execute('UNLOCK TABLES');9 Y0 K; ~# B  u8 O) N
  59.                         }& R2 u; e8 M0 I) n+ X7 m2 E
  60.                     }
    " M+ [1 y3 p+ Z. B
  61.                 }else{$ \4 G8 k  u9 f; M, Q; k4 o1 c$ E
  62.                     $data['msg']='非法操作!';, K3 N% E9 z& c5 z! c! p- p/ M" G
  63.                 }
    1 W2 h- N/ d' C5 f2 o! }# G
  64.             }else{
    ( ?' }, Y& q$ H; N
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';) {0 p4 ~, U+ g  Z; {% d
  66.             }
    + g4 o# h) }2 c: N' D- Q* K- `
  67.         }' e5 a# v. `% ^) N" u  A, e( I
  68.         exit(json_encode($data));
    7 X: i7 b% C0 R% E& l+ L
  69.     }
复制代码

  E1 y. U' }1 Y1 u
" E3 L  B; S+ v- i
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-8 15:43 , Processed in 0.145743 second(s), 21 queries .

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