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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

( c+ F0 U$ l9 }7 @
Mysql中的锁语法:2 `( e# r6 k7 j' B. c9 x8 }, J+ b
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
* y9 Q7 x- U5 C* R* {- kUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
% H2 F6 M; v/ O  ?" M+ yWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞- G. W/ H, t/ a/ C9 `! p
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :) h6 U* U" [( I% U
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
" Q; Y! D( T* Y/ \4 S( o( t) b测试时,有个文件就行,叫什么名无所谓
总结:
: I' |6 [/ V4 J; e项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
* Z& k$ F4 h9 ?0 X9 e1. 高并发下单时,减库存量时要加锁" X* X" a( U- R+ R4 @% d
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    * J+ }) m: p; d9 l4 P7 ~3 g
  2.     模拟秒杀活动-- 商品100件
    # J" ?+ `* j" j7 w
  3.     CREATE TABLE ta
    ( t2 Z- E' ~1 [  {8 e' S# ?
  4.     (/ z$ e. u2 |. o7 j) J
  5.         id int comment '模拟100件活动商品的数量'  |2 F% K  v* M4 g
  6.     );8 W- I% h4 D- ^# t4 P' m' d
  7.     INSERT INTO ta VALUES(100);, {. S( K+ V- T4 x
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    2 u# L7 w( O" o7 n. y8 C
  9.      */
    7 ~( k* [5 O8 t$ D% o( A+ S
  10.    
    5 q- i% p# q6 M! B/ t! ^( ^
  11.     // 关闭错误报告
    2 p; ?- B2 H, O& N7 ~. Y
  12.      error_reporting(0); ' B  q; ~7 d$ L* J- V8 B6 V$ I
  13. 3 u' v+ ^. l2 O1 C- Z8 N3 c- J- S' V( O
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    : m  U& R1 b& L9 ?% W9 o
  15.     $dbuser = 'root';            // mysql用户名
    # Z" z$ U3 o, b4 f
  16.     $dbpass = 'root';          // mysql用户名密码
    : \7 t0 S. I. ~' G% M
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);* @. K7 n# y; J) G/ j) f
  18.     if(! $conn )
    $ |7 ^7 t) }' `- |0 ^; F1 R
  19.     {- t2 N+ q( U0 l
  20.         die('连接失败: ' . mysqli_error($conn));1 V) K, z! f: R' i4 @5 l1 ^
  21.     }
    : j* d  K3 o# [7 H/ c" m
  22.     // 设置编码,防止中文乱码0 V' q7 p. ]* E- S$ q
  23.     mysqli_query($conn , "set names utf8");
    # c& ^0 U  M" n- K+ M  E2 P
  24.     mysqli_select_db( $conn, 'temp' );
    ; |9 L# n$ _1 v) _) ~
  25. 1 U3 y" d+ G  Z  |* [3 |3 Y1 ?# V
  26.     # mysql 锁 5 l4 q% H; O( @; U7 b3 A/ }
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 3 w1 }) R$ y! v% W
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); , `; U7 \. v( J' x0 I; y! G; c
  29.     $id = mysqli_result($rs, 0, 0);
    / ?6 |' |% A+ V0 Y/ b: T: H  _4 @
  30.     if($id > 0)
    6 W6 ]+ T& h- E% B6 a
  31.     { * J! f. y: |8 r4 m. |4 }
  32.         --$id; 3 c0 r8 z# X9 v7 W
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);   Q) u3 g0 Y  g7 J' q
  34.     } + g& A# M$ t* \

  35. 5 R; ]; U3 p5 h" f" U& q/ l( q) Q2 c! @4 l
  36.     # mysql 解锁
      H! v" D1 T5 |
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    * `; O8 P: o7 @; D7 a9 S  G6 |
  38.     //查询解锁后的id值
      |, e7 Y! L  K7 F
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');4 l: }. M+ B% c& ~* Q3 Z  ^  _- Z# m7 P
  40.     // while($row = mysqli_fetch_assoc($res))( I* ^1 |. j/ I, H& p' ^1 w8 G
  41.     // {9 n3 v+ Z: k( e4 B
  42.     //     $id = $row['id'];
    ) a/ o3 D  k- |
  43.     // }9 a/ s$ k* t7 t: f9 ]2 W
  44.     // echo $id;
复制代码

& \- a+ ^- P3 G, b" i' `
5 ~0 g) v+ A; }% L: ^
. E+ p6 b* P, L, s
PHP文件锁示例:
  1. /*7 O9 W1 G4 x$ V1 U9 N
  2.     模拟秒杀活动-- 商品100件
    . F" J" R- X% |$ r$ x5 j
  3.     CREATE TABLE ta
    * H  b; X; x) U# I
  4.     (
    . P% v- n4 ~4 L* M# _6 G9 [1 U0 R! v
  5.         id int comment '模拟100件活动商品的数量'
    $ \5 H  h5 c$ z- t
  6.     );' I* i: s0 F' ~9 v
  7.     INSERT INTO ta VALUES(100);$ w2 J4 B0 v/ A$ b
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件4 \( D0 g: e) v, Y6 r
  9.      */ 7 ~1 d" _$ W& l: r2 K) E' j! C
  10.    
    8 b/ i9 h: k6 N( x; h
  11.     // 关闭错误报告
    / }% g. k, n6 ?& m( X- x
  12.      error_reporting(0); - ]. j% q; l$ ]5 q

  13. 5 ^: H+ ^+ D: y, j; u8 E$ B
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    1 |& G( ]8 R0 R, g6 h
  15.     $dbuser = 'root';            // mysql用户名2 l6 Z5 n6 a6 }  M1 _3 h1 e2 y
  16.     $dbpass = 'root';          // mysql用户名密码
    . q7 n" L# k" A. k$ |" o7 u; w
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);5 H: B5 x4 ~; Y2 H* n2 [7 Q4 }
  18.     if(! $conn )
    5 A8 J" ^! o. r$ z# Y) d
  19.     {
    " q8 ~& q1 p2 h; P1 k9 W. w; W; N: o
  20.         die('连接失败: ' . mysqli_error($conn));
    ! \2 M6 e, [- w2 s% e( ?: K( P) i
  21.     }
    0 \) x0 K1 p( |
  22.     // 设置编码,防止中文乱码
    ! R; u8 w) L$ B% {
  23.     mysqli_query($conn , "set names utf8");
    1 N0 V% @; u. Y& X
  24.     mysqli_select_db( $conn, 'temp' ); : K1 e, R# i: M: g/ y$ A8 S

  25. % h8 \  W. G/ e0 x2 M) y
  26.     # php中的文件锁
    % |) C. G, F' n, ^
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    ' ]8 s3 a. I1 p5 S
  28.     flock($fp, LOCK_EX);// 排他锁
    * q& y% V8 X5 D0 D
  29. * h$ ~+ E9 C3 b  Q' ?$ ~& d
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 7 q( B- A4 v" C# _( _; L
  31.     while($row = mysqli_fetch_assoc($retval))( ]! A9 k. G! |2 A: t
  32.     {
    1 w) H$ X/ O' Y+ l
  33.         $id =  $row['id'];
    7 O: g. S" l  B  I6 R& _
  34.     }
    : G* x5 r) C  a% Y9 J
  35.     + p7 z0 F. A5 r. r" k
  36.     if($id > 0)
    ( x4 T7 C3 Y7 r! U7 a3 w
  37.     {
    # J+ d' |/ F! y. U4 P
  38.         --$id;
    2 ~8 w; y7 L& p5 S& s3 \9 P! Z/ {
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); $ p4 o% v9 Q6 d- y3 I& A& M
  40.     } 1 w4 B( B) D( j
  41.     # php的文件锁,释放锁
    & c) P* O( w: N$ b9 J* U
  42.     flock($fp, LOCK_UN);
    ! b  d8 t7 \  }) a6 b6 @
  43.     fclose($fp);" l5 t# \4 i! X8 J  I# Y
  44. ! F; r1 Q) z0 F
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    $ r) b$ U& D: p$ o6 C5 B6 J
  46.     // while($row = mysqli_fetch_assoc($res))
      q0 O# U$ H! D% x, [3 E% H
  47.     // {
    7 o$ {8 k% ?& S5 X( V4 g' G
  48.     //     $id = $row['id'];9 y; i; V% g6 y/ {
  49.     // }
    9 |' [- C* q2 x5 F8 V
  50.     // echo $id;
复制代码
* y/ u! }4 {$ O
, u8 S# `9 q3 g. M% E
抢券活动实例:
  1. public function envelopeSnatching(){! u4 F% C' Q' o6 t( ~/ z& f
  2.         $lingqu = $_POST['type'];
    * F0 P- O7 q  Y
  3.         $uid=session('u_id');//用户id# h# L- I$ w6 G$ M$ y
  4.         if(!$uid){( ]8 S5 {" K  b
  5.             $data['msg']='您没登录,请先登录!';
    / h5 V& w+ ]- g
  6.         }else if(date('Y-m-d') != '2017-12-12'){$ V9 y/ M2 p+ I* @9 s% O9 ]
  7.             $data['msg']='不在活动时间内!';! y6 ~/ o. b0 f/ S, a6 m, W' [
  8.         }else{
    7 J& v( \! K/ v& J6 O, _- z
  9.             $hours=date('H');//当前小时数7 K4 w4 u- X$ ?# T3 L4 T
  10.             if($hours > '09' || $hours > '17'){3 C9 C4 z9 [5 ^9 c6 d3 [

  11. - ~) j6 z2 s5 g( e8 w0 j
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的' \( Z! n1 P  I. d  x
  13.                     if($lingqu == 1){2 o4 T3 }( m% e% J
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    9 c; a8 T0 l5 L3 U" g  g+ q9 u- G
  15.                         if($hours > '09'){
    ! {, P- z$ X, w, R$ l2 U4 _
  16.                             $num=mt_rand(25,28);//优惠券金额
      N% D' l2 M, W7 Z, q4 e: L7 m2 }, z& Q5 U
  17.                             $id=1;/ ?% q, N1 T. K3 F; `9 N& r$ Y
  18.                         }5 c+ u% P: S) c6 E4 ~* |
  19.                     }else if($lingqu == 2){
    ! b' A7 O& {0 h3 }1 y
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    ' \* Z6 E2 U! s5 I  K5 b
  21.                         if($hours > '17'){
    0 p- o" l. O* R/ [
  22.                             $num=mt_rand(50,55);//优惠券金额
    9 \5 X- r, _- o$ J+ q' y0 g
  23.                             $id=2;; F. D, V" M8 C$ d
  24.                         }% |# X) ?" n# i% F( F* H/ x
  25.                     }
    5 B$ K/ K( h; C$ Q' Q  e: L+ e' N
  26.                     if(!$id){  K. K# J" ~8 k, B9 I- `
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    6 b: N6 _* N3 L% s# y) X
  28.                     }else{
    ) |1 R6 v" m% Q* ^' _8 Q
  29.                         if($is_lingqu){8 ?  h) H$ `5 {4 j$ O
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    9 q4 O+ R  m1 J: I8 U
  31.                         }else{
    2 _! |& E2 |) z4 C! X
  32.                             //锁表+ }, F' [2 D' y1 w5 Y
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    ! A. O$ e( d( ?) {; [2 i
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    / r& H; A( |; @6 `) ]" W
  35.                             if($active > 0){
    ) j! d7 H+ B% B; Q; I
  36.                                 //开启事务
    ( T3 Z) ]( T+ h8 ]* x" w
  37.                                 M()->execute('start transaction');  A7 e" V. [: S8 Z' g
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    2 x; k5 Y6 T: t4 C6 L
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    4 A% Z3 b) [, v+ W5 p5 P% p
  40.                                 $members_preferential    =    M('members_preferential');
    : E# H. O# N* f5 m, W
  41.                                 //对应投资金额,
    7 O+ ?& D( w# S( u0 h& Y
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ! L! v5 C7 _7 ~0 t" z
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    % [2 h# n+ R3 F2 i! Q. |1 n
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间+ E( A% E# x3 [1 j% M
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ; |4 {6 A6 _2 R, n
  46.                                 if($save && $add && $add2){
    " p( ~3 v: K( `5 G" G
  47.                                     //事务提交
    * i- [! D0 |( m3 F( a: e
  48.                                     M()->execute('commit');
    & H' p* J: i' E
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    / O: [  N0 _+ O! i1 F, m& l
  50.                                 }else{
    0 v! f, X( f2 j* o; X. M' l$ B
  51.                                     //回滚8 `$ p' _) T) U, [
  52.                                     M()->execute('rollback');7 i( p, ~( }8 ?* W+ ~6 O
  53.                                     $data['msg']='未知错误!';4 y% Q+ H9 x& f/ r7 Y  y; T
  54.                                 }
      K" Y: ^) K, p& p! D% X- i* `
  55.                             }else{
    4 L* `/ m7 k$ X
  56.                                 $data['msg']='红包已领完,你来晚了!';$ S* Q. Y! {! B7 s5 |; A) [! j
  57.                             }
    ; x5 H$ \/ x) ?# x& Y4 l# ]3 ^5 I
  58.                             M()->execute('UNLOCK TABLES');& u' F6 R" C' {
  59.                         }
    - Q  U' U4 T: L
  60.                     }
    8 T9 i3 B- x% T
  61.                 }else{
    ! X, H+ f* j( S8 Z; p0 j
  62.                     $data['msg']='非法操作!';
    3 ^& N# u& C0 \6 b! J+ d
  63.                 }
      e- u1 G+ s4 }4 c
  64.             }else{" M$ O2 k' C& _; A: T1 M
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    9 L3 o; v1 j- Q" K2 K5 w9 N2 u7 z  L- }
  66.             }# K# s/ a0 Q& _9 J$ K! W: x
  67.         }
    $ Y7 e2 [, X# n1 X* S6 p% ~; X
  68.         exit(json_encode($data));
    ) M7 l; [: o& X
  69.     }
复制代码
0 ^, G/ v1 I3 n
  j& n* _' n; p8 _
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 16:18 , Processed in 0.056913 second(s), 20 queries .

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