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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 9875|回复: 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://请求的脚本
复制代码
$ ~' q/ A% Y9 u3 f$ A
Mysql中的锁语法:
# w/ P- o' i$ b6 U! l8 J5 y% y& MLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
% a+ l. ]+ [# m, WUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
. H' e5 b* T$ N! f1 R5 e: xWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
% P  b+ X: v: W注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :& S$ K- X, f0 F2 u9 \; p- f
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
! _- G; q' e1 U8 g6 E测试时,有个文件就行,叫什么名无所谓
总结:
! Y: B+ w0 b, ~3 A项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
: i5 b" p+ n7 R' F9 P) }  e1. 高并发下单时,减库存量时要加锁
4 b" X+ B; p# S& Z6 \2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*# W! f3 F0 j" F5 S
  2.     模拟秒杀活动-- 商品100件
    3 U% l3 P5 |7 J0 ]& T) W2 K" N
  3.     CREATE TABLE ta
    7 g0 }0 a# U, z* z
  4.     (; I% U+ K/ |( c6 t4 I
  5.         id int comment '模拟100件活动商品的数量'
    : F# B/ a! y* Q" Z7 x$ @% l( z
  6.     );
    ( B& k; W! ~* X$ ^* p1 E
  7.     INSERT INTO ta VALUES(100);% f- k* b5 B& m: @1 v
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件5 k* \* {) p1 ]9 k9 d
  9.      */ % {9 Y+ h  P# C0 O
  10.     4 j5 t! F+ S1 W+ `+ ^+ T$ }
  11.     // 关闭错误报告4 h  `, F5 _. U& U9 F& k
  12.      error_reporting(0); 4 ^  L8 y7 d# l1 w. i  r& b4 a

  13. 8 r& c# h; c1 U6 ^
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址: W8 F9 v& T% a) n6 Y2 A7 N  W/ `, [
  15.     $dbuser = 'root';            // mysql用户名" i. X2 v+ J  G7 \9 m
  16.     $dbpass = 'root';          // mysql用户名密码1 E6 `$ H7 z' M" a: Z* d
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    0 V$ s: x! Q1 t+ F3 q
  18.     if(! $conn )
    0 e- b$ @: R& o* ^* P
  19.     {6 _# D: [/ }6 `$ s( @2 u) z
  20.         die('连接失败: ' . mysqli_error($conn));7 v- b: t# N1 ^: S6 D& J
  21.     }" G* q& [) ?4 E- s8 _
  22.     // 设置编码,防止中文乱码9 [1 ~# O2 K) a( h' [
  23.     mysqli_query($conn , "set names utf8");3 c1 v* F/ V+ r0 ~
  24.     mysqli_select_db( $conn, 'temp' );
      }! i( G4 t6 d: _( B; E1 i" J9 D
  25. 8 k: t, K% {- ?+ c/ V4 c2 k
  26.     # mysql 锁 9 ]9 G8 |8 g" x. K. E
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 , O9 Z# b8 l1 C
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    1 A7 N4 O  ]$ h% t8 c* [# v
  29.     $id = mysqli_result($rs, 0, 0); , b. t2 k/ Q( n& l
  30.     if($id > 0) + K' l" y, W. R% F+ E
  31.     {
    # {5 S# H) o  E0 }% y
  32.         --$id;
    * }5 Y# W; T3 B( y9 N
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    : r; ^) ?, f; M+ d7 M; T9 j
  34.     } 1 M$ f6 U% T- U4 Z; v4 S" V

  35. - D# ~3 M6 O7 @, y" a
  36.     # mysql 解锁 $ l" S4 P& [3 M. s8 j, x5 e
  37.     mysqli_query($conn , 'UNLOCK TABLES');. u' B! `+ W5 @8 p! T+ ^
  38.     //查询解锁后的id值8 ]1 P5 Q0 n% H' N3 E% _" a4 @' O
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');# e- o& g; i: t
  40.     // while($row = mysqli_fetch_assoc($res))1 c4 {- `; K/ \8 k6 d: S0 u9 x
  41.     // {3 q! `- v0 B. P- ]. Y) E) L, g
  42.     //     $id = $row['id'];: w+ K9 y1 I( h$ B
  43.     // }
    2 G  A0 P* m; s% s/ H9 @
  44.     // echo $id;
复制代码

: i! ^& w$ o; [8 E
6 c) W* ^" _# W: b6 B/ Z
1 |( A! Y8 y$ J5 v
PHP文件锁示例:
  1. /*
    / O! P* a! ^6 Q7 s9 y" |5 W! _" i0 U
  2.     模拟秒杀活动-- 商品100件
    . |7 G9 Y/ h; E' m
  3.     CREATE TABLE ta" H- v8 ?3 e/ Y
  4.     (
    : O8 l3 E! D: C6 e+ |" X% E: |' B
  5.         id int comment '模拟100件活动商品的数量'
    : [& Y" y- t' E/ O
  6.     );) j% H3 I2 F& M. d! q
  7.     INSERT INTO ta VALUES(100);
    9 r- K5 m* q( U  @
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件; n5 l+ i1 m. ]4 F: E
  9.      */ 6 _# q" g( F7 Z
  10.     : @' {9 s& N7 i, ~6 X5 o
  11.     // 关闭错误报告) O+ o  U3 T: s" N. B
  12.      error_reporting(0);
    * l' U9 y6 F/ K! d

  13. 5 ]! E1 T3 ?: A# b* T: F
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    ' }  S+ _3 L- A3 Q* y6 T3 V! }
  15.     $dbuser = 'root';            // mysql用户名
    / Q" U. v, W! e5 O$ W
  16.     $dbpass = 'root';          // mysql用户名密码
    # Y8 k2 ~9 ^' h3 t2 M9 h
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    : K8 ^( b5 O! ]' ]3 S7 r; Z% F
  18.     if(! $conn )
    , h& c1 J. M: |/ _, V: d
  19.     {
    4 Q# x; I2 m' b( e; d) `) X
  20.         die('连接失败: ' . mysqli_error($conn));; h3 n- H8 N+ }: B  L
  21.     }, B9 Z: `7 {- E  {
  22.     // 设置编码,防止中文乱码9 [) o5 H- B9 P4 _
  23.     mysqli_query($conn , "set names utf8");1 W) T7 v/ Q/ h7 [1 t/ Y6 _) A
  24.     mysqli_select_db( $conn, 'temp' ); 2 ^- a( g4 `7 C, Y6 B, V4 W, O$ {& a
  25. ' ^! u0 Y4 Y" Y9 B' A& Q  T- C: v
  26.     # php中的文件锁 ( a8 r- }) e# b3 g7 n! D! T$ ~
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 * }9 D* q6 @) M% n' s$ t/ p5 Z# a
  28.     flock($fp, LOCK_EX);// 排他锁
    & K" m: v# i* G6 C) |  c) O
  29. 0 u7 m" C# j& k& m# I
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 4 Y3 s9 }& S2 L. s
  31.     while($row = mysqli_fetch_assoc($retval))6 {$ E! E5 T0 p4 F" z  P; E! Q( R
  32.     {* ^% l& d* _$ P: t* d
  33.         $id =  $row['id'];
    ( ^! z; j; Z8 r
  34.     }) H! t5 D# J! \% g5 Z; s: F
  35.     ! r" ]2 C6 o1 Z: m. O1 q" M
  36.     if($id > 0) 4 c# ~; R7 I8 D
  37.     {
    4 b3 \3 V1 p( A: V
  38.         --$id;
    ' C2 a# x' ]8 N, X
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 4 k4 I7 u, Z" T1 ^' V% |+ K& w  H% Y. ?
  40.     } 0 k2 A% D/ g) G  z* D4 T
  41.     # php的文件锁,释放锁
    , O  ^. V: |! ^1 d1 v3 j7 o1 J0 N
  42.     flock($fp, LOCK_UN); 6 @# R4 O6 J' x. |) y8 k" A* Q
  43.     fclose($fp);
    : z2 T6 D  j4 A" x
  44. " S# Q2 L' c( P+ u; r, h/ E
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    5 _' I$ E5 K5 D( x
  46.     // while($row = mysqli_fetch_assoc($res)); e7 D2 o) c, V  O* P
  47.     // {
    2 A& Y, b! s! ?9 {1 x
  48.     //     $id = $row['id'];
      c' Q5 S; k* h$ h! ~; L# H$ E
  49.     // }* L2 B4 ^9 |( H
  50.     // echo $id;
复制代码
9 c( d# C+ \! g/ E, r& {; u1 x
: B% q+ U, [" Z* G
抢券活动实例:
  1. public function envelopeSnatching(){7 ~: n1 G1 n) ~! {7 w% T0 X
  2.         $lingqu = $_POST['type'];
    4 q6 Z& [8 i+ S9 V' M. @
  3.         $uid=session('u_id');//用户id+ r( z& x7 r0 w% |
  4.         if(!$uid){
    5 ?! T2 T* w- R$ i
  5.             $data['msg']='您没登录,请先登录!';
    $ N$ }2 X* ]3 E* U& I$ u$ I
  6.         }else if(date('Y-m-d') != '2017-12-12'){; o& x" L/ D8 }3 O
  7.             $data['msg']='不在活动时间内!';
    5 a7 }) `4 |4 _' G4 I, N
  8.         }else{" [% J8 M$ \; D6 T/ J
  9.             $hours=date('H');//当前小时数9 G5 y# O: x) Q6 q
  10.             if($hours > '09' || $hours > '17'){
    * D3 R' f+ k! L1 j% B- v" C

  11. * n- P- Z- V- ]3 K& M6 x- w, k
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
      O- d, K1 H% V5 U+ J* l( Z4 v# x+ @
  13.                     if($lingqu == 1){
    , G4 L- L* A' m7 ?8 R$ S8 e
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过4 f- F& U3 @/ C' V8 [0 V3 t
  15.                         if($hours > '09'){
    ! ?& K. `+ N& @1 h
  16.                             $num=mt_rand(25,28);//优惠券金额
      s8 q$ v4 d% A3 X, L
  17.                             $id=1;
    ' M; v$ I' y& ?8 \/ h8 q
  18.                         }. v9 y: @+ T9 f9 @) K: l+ J* j+ v
  19.                     }else if($lingqu == 2){
    3 _3 |9 ?: u: l. U7 M) @& Y% W
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    3 C0 ?+ T6 P9 f( t2 i
  21.                         if($hours > '17'){
    + n* N: b; R4 K8 w3 [, Q2 ]0 I$ N
  22.                             $num=mt_rand(50,55);//优惠券金额9 O3 p1 j' x* [/ c. n9 B
  23.                             $id=2;- r* j5 }( O3 q% Z8 e7 b
  24.                         }6 V2 b/ ?6 a* a/ S& h
  25.                     }
    + t+ Z: e/ f, `, j& p. u# V: J
  26.                     if(!$id){
    ; I3 z* f/ w3 z) d, z
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    5 ^" e' B8 K1 T3 A8 J9 p
  28.                     }else{
    " s( e! Y; _8 M2 i) E7 o6 T5 y: x
  29.                         if($is_lingqu){: E2 R0 a' D* Y
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    - ?% ?! Y4 |0 t0 D, t- L, u
  31.                         }else{+ L* O5 B- c9 R  J# G
  32.                             //锁表
    : k' a, ~. u6 N& o, g" ]# D
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    0 B  k9 S3 b( U. K4 F& E- a- F- s
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();5 f6 s1 X. M8 J
  35.                             if($active > 0){
    & ^. p! q- m# Y3 i( i0 f$ @
  36.                                 //开启事务, b: w& m9 e0 D. w6 y. I0 l+ o
  37.                                 M()->execute('start transaction');
      D* v' T, Y2 ?7 h2 o
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));2 O  y. G: Z7 s' Z' _, ^2 C# G' J
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    6 G7 V" q" S0 m  u# {6 G
  40.                                 $members_preferential    =    M('members_preferential');- e" i# X! x: D
  41.                                 //对应投资金额,
    # N& ]) \' R2 E( F  N  w1 U% [
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));" }3 j4 T* N) S! e* m
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    + m# h  P, u: j+ S$ w: Z" H
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    + M5 n# B; Z( \" u
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券, ~* F* g0 m! z, e
  46.                                 if($save && $add && $add2){* h* p9 Y" r. R; Q
  47.                                     //事务提交8 f* ~% ^4 t3 v
  48.                                     M()->execute('commit');1 r; W4 Z; H, I3 }+ E! u% {" C- ?
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    + f. y8 M2 S. v0 B% _) r
  50.                                 }else{3 c3 x- W% B6 J) I! N, P/ c% B
  51.                                     //回滚/ h; z: u7 b  P/ I( w7 d9 e
  52.                                     M()->execute('rollback');0 R) X1 P0 E8 h! r( h6 k: l
  53.                                     $data['msg']='未知错误!';
    ! J  J' i" U% k2 C
  54.                                 }
    4 t; i1 Z0 w$ j
  55.                             }else{
    0 B: r9 }; f# l, E; F. j: M
  56.                                 $data['msg']='红包已领完,你来晚了!';/ y9 h! V; [/ |$ s3 G
  57.                             }* I0 z% A( P* c* s3 I$ A7 Y
  58.                             M()->execute('UNLOCK TABLES');( H1 F6 o( j. _6 Z
  59.                         }
    ; |6 K# C0 J  u( L7 U0 Z
  60.                     }" a: P2 Q8 r# a4 O1 K3 [4 @+ h
  61.                 }else{2 d1 I' l& y3 D  Q: |
  62.                     $data['msg']='非法操作!';
    # k' q! r' w# N/ Z5 \
  63.                 }4 }* v0 [" F9 N5 Y, V
  64.             }else{
    1 G0 C" s$ b: l! d8 y/ X8 @1 z, C
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    * C0 \" l" F. h) l
  66.             }
    , h0 [' ?2 M) n% J, F
  67.         }9 _, c) C3 C2 {
  68.         exit(json_encode($data));  _7 O9 `, X) `- U/ d- D
  69.     }
复制代码
' `8 C+ ^" u; l. _  x. R% w, Z
9 T$ Y. A! u# S2 T" ]+ E0 N& f
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 04:20 , Processed in 0.060313 second(s), 19 queries .

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