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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

) _6 d* S+ u2 O- m  L6 Q
Mysql中的锁语法:
" ?9 ^8 R* {7 H6 G5 Z2 mLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】/ R( }* ], l+ d2 O# `9 F# K" @4 A4 C
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表" s, w: a  k, ]9 I! r
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
. O9 F: \$ V4 x* v. g* h注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :9 e! ^& E5 W2 b2 u3 {
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。2 e7 \$ v( W2 ~% ^( R% \
测试时,有个文件就行,叫什么名无所谓
总结:
# D( f8 s1 k' ^3 P+ ^. j项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
  K( h$ \2 c5 y- j1. 高并发下单时,减库存量时要加锁( n* L  I! T: g
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    0 W7 u1 v9 n6 ]6 a- H( b9 }) k. ?
  2.     模拟秒杀活动-- 商品100件- ?" X% ^: t' B. [9 A
  3.     CREATE TABLE ta' D6 G: a8 F9 p
  4.     (* J& `6 G1 g% A
  5.         id int comment '模拟100件活动商品的数量'
      \4 `( \2 }/ k7 _) N
  6.     );8 M9 y& O8 _# O  P5 j3 t: k$ N2 r
  7.     INSERT INTO ta VALUES(100);
    " m' D; t3 r% u6 D
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件/ l6 w% {8 r$ J" \/ o6 e6 _  u- Z
  9.      */
    1 N* a& P" ?7 Z
  10.     3 J: s4 q$ k; U2 {  B( ]3 s
  11.     // 关闭错误报告
    , s/ z! h& q( C
  12.      error_reporting(0); 2 r6 N" T* u- }
  13. 5 i& v: d$ a3 v4 I4 x
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址1 r9 [$ L& |9 U% Y6 @7 Y
  15.     $dbuser = 'root';            // mysql用户名6 q* i$ B% r& Y5 }* A
  16.     $dbpass = 'root';          // mysql用户名密码. ?" f  H% A7 v2 {9 C3 n
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    1 [  n, }9 Z, v2 j* S
  18.     if(! $conn )! h  t2 ^* _: i9 p6 Y7 A
  19.     {! a3 Y7 g' K% }9 s
  20.         die('连接失败: ' . mysqli_error($conn));7 x' _( k% c9 Q, u4 N
  21.     }
      \: z5 i5 c+ C& H5 }( H# ^  B
  22.     // 设置编码,防止中文乱码0 K% H* |$ J: }' B3 U5 A
  23.     mysqli_query($conn , "set names utf8");
    8 C3 k3 y- j" r8 k6 H4 p* [, f1 b- j
  24.     mysqli_select_db( $conn, 'temp' );
    2 n: X4 J  L2 @9 f5 u7 T/ i1 E

  25. 1 ~6 A1 o' @$ z  c
  26.     # mysql 锁
    0 r' d6 V  |: ^5 E( Q+ _! s
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ; s: F$ d5 A, O9 D) d; A
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 6 j( i% U6 y& b2 E
  29.     $id = mysqli_result($rs, 0, 0);
      o; s) e$ ^1 R* J+ i0 a
  30.     if($id > 0)   D( s4 ~2 k. R  h2 j
  31.     {
    ! u9 a& l/ B5 w7 D6 `- V
  32.         --$id; * K9 d+ {! C5 F* s* A/ L
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); , }; U# B& F( O* s& e
  34.     } ; t3 a% O7 u$ d1 b! t
  35. 2 [0 P9 e5 r4 \! e9 h# I
  36.     # mysql 解锁 , g" R9 }% K) F8 Q% H
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    2 o2 K% i( {5 d; k4 G
  38.     //查询解锁后的id值
    " t6 a' `1 r) n) }
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    8 i( _+ a) F, M9 R* p
  40.     // while($row = mysqli_fetch_assoc($res))7 ?9 T# ^& Y; S: n+ \! y  N
  41.     // {
    # X$ n+ |7 s: P% O7 ?0 ~: @
  42.     //     $id = $row['id'];5 |+ ]/ t- x9 Y" M
  43.     // }6 i* o. R+ ?9 c; r) x8 C
  44.     // echo $id;
复制代码
7 p7 o* ]3 A5 v
' n  w* y" r# }; G2 L
- F2 e# k1 a& U$ I6 j0 X* K
PHP文件锁示例:
  1. /*
    $ ^4 }8 h. P: W
  2.     模拟秒杀活动-- 商品100件" n! q5 z$ K' N& Y/ l; I
  3.     CREATE TABLE ta
    6 R. X1 M+ s. T  I2 |
  4.     (# ]9 w$ h# z5 I) ?& {2 W; X
  5.         id int comment '模拟100件活动商品的数量'
    , ^  b: \& n, w1 L6 y$ a: R
  6.     );
    # ]/ O' V4 u: @3 P
  7.     INSERT INTO ta VALUES(100);
    " U. m4 V; T/ L* T& `( Y( [
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件' T7 A% C: T8 U' l* E# l; {
  9.      */
    + S& U9 y- g& B5 B/ q$ r6 l2 Q
  10.     ) K% Z/ ?1 [" b, ^* Q2 K1 X5 J* {% i
  11.     // 关闭错误报告6 L2 y8 i, o* S3 L4 j* _5 [
  12.      error_reporting(0); ' o7 G5 z- v" W" q7 {

  13. . |3 v5 N& I3 L9 \
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址/ M/ z) R/ R+ O' ~/ C
  15.     $dbuser = 'root';            // mysql用户名
    ! Y, c1 z6 S6 {; e; G9 v3 e& I
  16.     $dbpass = 'root';          // mysql用户名密码
    . a. j8 Q6 F- o
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    / q1 Q8 H2 r& ^8 k9 P
  18.     if(! $conn )& P# x- B, r; g, R; u" Z* W
  19.     {
      R, ]; w5 \1 [! [5 ]/ D
  20.         die('连接失败: ' . mysqli_error($conn));
    0 T- ~* T& y3 f! i
  21.     }
    & O2 N# u5 v! F6 n  Q% M
  22.     // 设置编码,防止中文乱码
    " w$ A; T$ q8 p' a; `. I* Q
  23.     mysqli_query($conn , "set names utf8");
    ) u9 ]2 X0 r& g/ w" r% b1 Z- j
  24.     mysqli_select_db( $conn, 'temp' );
    - D" P" {- Q; f; E

  25. : c' ]  J; u% r' [# y/ n
  26.     # php中的文件锁 6 U! x, \* D8 e5 [' M- U
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 9 L  @: M: u5 A; `2 D
  28.     flock($fp, LOCK_EX);// 排他锁
    ) @5 b* V' Y  l  Z: j

  29. 3 C6 h4 G/ c% [& r
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    5 {1 c' o# q0 A, f$ }6 g
  31.     while($row = mysqli_fetch_assoc($retval))' L3 m4 L% a$ S2 k5 s% l8 |. P
  32.     {; M3 J* m- l4 c& H0 q( P
  33.         $id =  $row['id'];
    " z6 I! w, Q4 Q- \
  34.     }
    ' K- Q: U/ s# P+ j2 ?
  35.    
    + ?+ d8 S( @% f* }# M
  36.     if($id > 0) 5 O7 y* }/ ], B" U5 y
  37.     { 6 X" H% `  d# q9 b0 u8 }  e
  38.         --$id;
    2 Z4 a* a; g9 j$ L" d
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); * q) t* b0 A/ g- z$ K, _  x& t
  40.     } , f1 l5 q# ^3 S2 f
  41.     # php的文件锁,释放锁
    ) Z. |  M  {  N0 K3 `) ]
  42.     flock($fp, LOCK_UN); ) F# R& w# J  f6 D! X
  43.     fclose($fp);
    - j2 A& Y1 s9 b2 J# Y0 w- k

  44. 9 X2 U! }7 ]+ X3 L# F0 \# q2 }, k
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    3 ~1 a# m5 @1 C7 y* M
  46.     // while($row = mysqli_fetch_assoc($res))/ r# S' D3 }* t
  47.     // {# i* Z( l, E8 ~- m$ w
  48.     //     $id = $row['id'];
    . z4 [" y0 a% `/ u* o* F' @
  49.     // }5 H4 r# p* p" i8 p/ Q3 i0 K. P
  50.     // echo $id;
复制代码
* r! }4 _: ~; _% a

; E; z4 E( w  i
抢券活动实例:
  1. public function envelopeSnatching(){
    % s) ]$ A' s. k, l5 Y7 r" p" {
  2.         $lingqu = $_POST['type'];
    ! G. K2 N+ D/ `# n
  3.         $uid=session('u_id');//用户id
    , [! M7 b$ V3 d
  4.         if(!$uid){, A/ _! H6 i  M$ W0 W% w! J5 k
  5.             $data['msg']='您没登录,请先登录!';. i* v. a3 [! f# y. V8 H
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    ) u# Z+ i8 V- E  g/ I& Q
  7.             $data['msg']='不在活动时间内!';# G' x" H4 o4 y* b
  8.         }else{: o/ z# `+ m; ?1 y5 k$ `/ u
  9.             $hours=date('H');//当前小时数, _. g7 Y* P" G- V1 N  e8 V
  10.             if($hours > '09' || $hours > '17'){: {* f7 l/ w  |
  11. % a8 ~! e. Z" s7 I& F) R
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的+ o# ~4 Y' |* G5 Z* ?0 X
  13.                     if($lingqu == 1){
    3 z! E1 E  q) z- j( I
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过6 j0 ^( H( |9 g
  15.                         if($hours > '09'){
    * J) V3 V+ C: `! l* I8 R1 }
  16.                             $num=mt_rand(25,28);//优惠券金额
    8 {3 c, g- d, l1 [8 L
  17.                             $id=1;
    9 A4 \2 N) t" x2 R
  18.                         }7 h8 `5 A: A0 s3 O9 p( [, x
  19.                     }else if($lingqu == 2){
    ) r" T# J" r- ?% z- t
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    0 c( W$ d1 e# I' S; `% y! j& \3 J: Z
  21.                         if($hours > '17'){
    ) J" E7 F$ `4 _. Y  H
  22.                             $num=mt_rand(50,55);//优惠券金额3 [3 Z$ g7 E/ t& b3 |& C7 U. f' T0 t
  23.                             $id=2;
    - j/ f& R7 G' ^+ F" I8 t6 N
  24.                         }
    4 C$ \6 P8 `* n
  25.                     }
    ( D* _: K6 L9 i. t! M4 H
  26.                     if(!$id){
    4 X' i" C. _& D% T4 h/ d7 A, w
  27.                         $data['msg']='时间还没到,晚点再来吧。';3 _1 M. n* ?3 m4 `, Z5 L; d" W7 S6 G
  28.                     }else{
    : X1 l5 `5 g# n" o
  29.                         if($is_lingqu){
    * T: l+ r0 k( |/ I; `# P
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';/ f  @! f  S) R" E$ A  u
  31.                         }else{1 z* t. `6 r- \0 c# q' s2 o5 D& ^
  32.                             //锁表
    4 H5 R1 M( S/ a8 i% m
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    # F! I# d' I7 S' ^- A9 h: t/ G9 w
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();: J8 {( g4 S; o/ h) J- R
  35.                             if($active > 0){
    ' ^! j% {+ Z9 ?6 V/ p
  36.                                 //开启事务4 T. v# T+ x% C. V! K
  37.                                 M()->execute('start transaction');  N! d! k! i% a+ K& W; c
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));' g1 P4 J8 E, a% q
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    + f, D+ R8 A" p# d1 Z/ H" ~0 K3 q
  40.                                 $members_preferential    =    M('members_preferential');
    * h( j2 Q$ M3 @3 `
  41.                                 //对应投资金额,; `3 C7 T# x+ U9 u" D! p7 I
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));2 H5 ^- O7 i9 C  c  c; S$ K, u
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    9 A7 h% I- e9 z  u/ v2 ^  p
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    . j: z% z' M' w; O( X! W
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券1 _- C+ k1 C) n* R: q. J) {  }
  46.                                 if($save && $add && $add2){) C$ a( g: U9 M$ S2 d
  47.                                     //事务提交
    $ X. P' y5 d1 i/ b/ `. B
  48.                                     M()->execute('commit');
    ; m& n/ v* B- p# b! i( J
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';+ W$ U+ j. d2 B3 O  a* k
  50.                                 }else{/ h- N6 [$ S4 [% l7 B2 L- Z- O8 _5 h
  51.                                     //回滚' R8 x+ L7 z: u/ h3 M
  52.                                     M()->execute('rollback');
    0 Q( Y3 B1 ?& Q
  53.                                     $data['msg']='未知错误!';4 Y; C# L) ^* b* `
  54.                                 }- R& H3 L: M) L) M8 I
  55.                             }else{. ]9 k2 G( U/ x# k( h0 ~. v
  56.                                 $data['msg']='红包已领完,你来晚了!';/ X/ w! _+ F7 i) T6 Q
  57.                             }
    1 u1 ~' {7 V/ ]+ z% D
  58.                             M()->execute('UNLOCK TABLES');' T) f6 _& m' m/ B  Q) T5 [
  59.                         }
    0 X! @" x: n; c' l3 k/ `
  60.                     }
    0 c' X/ X* X( r2 o# J  o9 ?
  61.                 }else{3 @% b' R0 J) ~) g; {* n& U
  62.                     $data['msg']='非法操作!';$ L# n" s0 p9 `  h) O2 d$ q
  63.                 }% L$ Y4 B* K! V/ K0 O
  64.             }else{1 v  N. Z/ s. m0 M, T* h4 y3 P" I5 N/ K
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';* e. y/ g; x/ B; b8 w2 @
  66.             }) r6 F6 x0 n7 L/ L. j( h( N
  67.         }$ h& f4 U/ q7 ^1 ]& j' }3 A
  68.         exit(json_encode($data));$ ~4 m" Y4 W& E' G* O9 o6 y
  69.     }
复制代码

: u" Q4 Z8 t2 ]) X4 c# U1 j2 x; Q
+ i, P3 O8 G9 b8 _
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 21:54 , Processed in 0.087723 second(s), 22 queries .

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