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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

" P( S- ^7 l& h+ d1 W/ p/ J
Mysql中的锁语法:
3 C. W' H4 [9 L6 s" ~LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】4 k; i8 }/ ?8 b# k
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表2 A0 M( U; j9 ?$ H* `# T0 o
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
+ r  q$ E8 _2 J1 g" o  }7 q注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :( q& s- I5 Q& ?7 I
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
6 |1 t8 d* ?9 v' o* A5 o测试时,有个文件就行,叫什么名无所谓
总结:$ o4 h# p. e7 @8 [0 Y
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
* ~+ [7 C/ i3 W3 \4 M: v0 k1. 高并发下单时,减库存量时要加锁
) z. @+ {2 R7 |3 O2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*  g  K9 W' D1 C  v7 J- E+ [9 z
  2.     模拟秒杀活动-- 商品100件
    # U6 f' ~4 c) v% L; Z
  3.     CREATE TABLE ta
    + c7 I' p# i" P- W
  4.     (
    & P  s, x* a! r9 D; ^/ N. u- [) @
  5.         id int comment '模拟100件活动商品的数量'! F% c3 k$ Z2 F$ b
  6.     );
    5 j+ E) W/ }# [8 l! Z
  7.     INSERT INTO ta VALUES(100);5 F4 N5 t4 s6 g8 |
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    # ?$ [) ^$ U( a. B1 {
  9.      */
    & n1 X  j* B4 |* l
  10.    
    * @' b8 o' N( {0 l1 ?% T7 s* j. i8 l
  11.     // 关闭错误报告3 b0 D# M( l+ V3 N' [5 i. G( y
  12.      error_reporting(0); - x) C3 e. K* K, L
  13. 7 U7 c4 k1 U* f& o4 q9 B
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址) H) l8 j. C! ]# n2 C6 p; e  y" `1 L
  15.     $dbuser = 'root';            // mysql用户名& v* L5 l8 [9 s9 x1 {5 v
  16.     $dbpass = 'root';          // mysql用户名密码" x" l0 C) `8 h# g4 q& `
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);, \! l" s  y1 I
  18.     if(! $conn )/ C" \8 ], r+ ]( t" T; q
  19.     {
    ! o" ^0 a6 V1 H' x2 O
  20.         die('连接失败: ' . mysqli_error($conn));
    % N+ P8 c# T; P9 y' L: T
  21.     }8 T  U/ C' }( [' h5 O# X. D
  22.     // 设置编码,防止中文乱码
    # [; @8 [, `7 A0 }, L  h
  23.     mysqli_query($conn , "set names utf8");7 `- p' R* \# C5 G% C
  24.     mysqli_select_db( $conn, 'temp' ); 9 I! y  _* p0 F; M- F' d

  25. , F" n3 G  O' w& d. C& n: u, B
  26.     # mysql 锁 6 O3 c! y1 {7 G5 W) e9 M3 P, q
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这   W6 K  n* Z# S7 I8 l- H. l, {. E: w# g
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); $ J# H/ r9 R6 V/ f
  29.     $id = mysqli_result($rs, 0, 0);
    8 I$ L; r. t2 y2 z! L) i5 n: R5 ]
  30.     if($id > 0) 5 C9 Q; `* V) A4 c' {' J- N
  31.     { 8 g9 u! H" k- y  {
  32.         --$id;
    ' E5 u2 s3 \# `! p
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    ' a9 c* ~3 d( @2 y
  34.     }
    ! X% h% S5 A' i/ E" v1 x
  35. * f4 [1 ^# A+ ]8 m+ p
  36.     # mysql 解锁
    ' r0 ]5 r# m4 v+ f
  37.     mysqli_query($conn , 'UNLOCK TABLES');: Z, m7 U4 v7 J2 ]# c
  38.     //查询解锁后的id值
    1 X$ x3 K8 g* x! j
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    6 l# j+ v$ C; f. C3 s) v$ n7 ]6 W
  40.     // while($row = mysqli_fetch_assoc($res))- ^9 R; k" C9 `1 q7 J
  41.     // {2 I- j' L6 B: Y3 Y
  42.     //     $id = $row['id'];" W$ B, [& R6 O$ s9 B+ p! P
  43.     // }
    ! P: Y* f* B/ G5 D$ h2 T5 _1 ?
  44.     // echo $id;
复制代码
/ L- L% S& q4 n) ?! j( e

7 s/ y- @( J: V% p) D5 N, Q$ m

, ^/ v: }6 J; Y8 ]9 f3 J4 O
PHP文件锁示例:
  1. /*
    2 W8 ~" i- Q! M# m
  2.     模拟秒杀活动-- 商品100件) }9 x6 T7 H9 b  S
  3.     CREATE TABLE ta
    # D7 p: L' k5 ]+ F1 \. k
  4.     (- _6 i3 U( i2 s7 y$ T* h$ ^1 `
  5.         id int comment '模拟100件活动商品的数量'
    ; K; p9 g5 N% I& C/ D
  6.     );
    ) G' J9 r  b% Z- f% B
  7.     INSERT INTO ta VALUES(100);
    % g& c8 G+ w- s( o4 Z
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    9 ~- ~; t% i, _, B% Z" \
  9.      */
    7 X* p# ~$ X. P1 P! t: h1 b' E
  10.     % p. i$ M" d  p4 |
  11.     // 关闭错误报告
    1 T  [. n$ t  p1 P
  12.      error_reporting(0); . q2 I  q, l" l+ M0 D$ x& Q

  13. : n+ d' }  O8 X% D1 ]0 f
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址& t* F! M6 B8 L* ~3 v4 n
  15.     $dbuser = 'root';            // mysql用户名
    . y* \, u, g; ]$ p* S
  16.     $dbpass = 'root';          // mysql用户名密码
    " {" L( T6 o* L/ N" Z
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
      ~" w, w2 B: V  [
  18.     if(! $conn )# \: o% `9 r" r
  19.     {
    ) Q) }: F" ~$ H$ r% V
  20.         die('连接失败: ' . mysqli_error($conn));
    & a* E6 m7 Z/ l* ]8 V* A
  21.     }! I* c4 ^# P: V+ l7 V; [+ Y
  22.     // 设置编码,防止中文乱码
    # `% i1 _: E* B$ w+ V1 l
  23.     mysqli_query($conn , "set names utf8");3 z* y6 r" p$ J! p/ ?
  24.     mysqli_select_db( $conn, 'temp' );
    % [6 L, d- J- {2 E& n$ a7 B
  25.   N5 g) B  \- q- w: G" c
  26.     # php中的文件锁 7 W: a% J, |: w9 v7 T. B- [; M
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 * X, }( J. Y6 w; O
  28.     flock($fp, LOCK_EX);// 排他锁
    $ W( t+ ~* j9 V1 o+ m

  29. 1 Y2 d" W# D7 x+ @1 j% o6 L
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    , v. O! m. s. C$ y4 J. o( `2 M- |
  31.     while($row = mysqli_fetch_assoc($retval))* z3 E% X. V, S% i) @3 {: k
  32.     {
    + I: k4 U1 a4 \, c* A% n% H
  33.         $id =  $row['id'];
    - o+ x! h; U" i1 \- ?$ H
  34.     }8 |! Z5 F" d* c( k; ^, Q
  35.     " G+ \& R( R: u; v% d7 N  s
  36.     if($id > 0) 0 O* j: N) G: b6 D" O  {, B) x
  37.     { 9 M( |( y8 [7 R9 S+ R
  38.         --$id; 5 n1 g5 T& _& M$ B
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 9 w+ O+ c5 d4 I* U* [9 M5 ~
  40.     }
    ' R3 h* P. Z& Z8 p' X+ E/ T: b
  41.     # php的文件锁,释放锁 / h& S1 a% o, y! B
  42.     flock($fp, LOCK_UN);
    ; n/ `$ _+ N: v5 @* L
  43.     fclose($fp);
    8 Y3 A' j1 S+ h( n' C/ b6 d' \* A

  44. 3 X: ~2 B8 A( G
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    + T: B+ w, g/ S* T0 }% p
  46.     // while($row = mysqli_fetch_assoc($res))8 Q3 U4 p; ?" {. B9 e" k
  47.     // {
    8 R% F1 T( M5 k( Q
  48.     //     $id = $row['id'];
    ) u) O/ n. z3 J  r. h: L6 M4 `
  49.     // }
    . i& m( y  u8 c% G+ @& O
  50.     // echo $id;
复制代码
5 i/ a7 V9 w1 Y2 i- L" C

+ J. d* c* P* G) j+ @3 b) F
抢券活动实例:
  1. public function envelopeSnatching(){
    3 z; F" _' M3 ?& e$ \8 E
  2.         $lingqu = $_POST['type'];' c& h. e' B  U1 i
  3.         $uid=session('u_id');//用户id% l2 P) U; j. L0 p0 R
  4.         if(!$uid){: _! E7 X* }1 S' V
  5.             $data['msg']='您没登录,请先登录!';5 m5 u( m$ ?! g- {5 G
  6.         }else if(date('Y-m-d') != '2017-12-12'){0 f3 r+ l  \  X7 C
  7.             $data['msg']='不在活动时间内!';
    ) ]2 `( s! z+ V7 }/ U. D* D7 A
  8.         }else{
    5 N1 c: t% [/ i. o% V6 H
  9.             $hours=date('H');//当前小时数
    : b' e# y2 T- A% Q
  10.             if($hours > '09' || $hours > '17'){3 C" |3 f8 G+ N1 f

  11. & M6 i4 X& K. P* A" Q
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    % J- O" {9 ]5 a8 ]" d
  13.                     if($lingqu == 1){8 L5 W' c9 `2 x
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过4 d( b/ L  c" B- c
  15.                         if($hours > '09'){4 [7 T6 R' p$ T
  16.                             $num=mt_rand(25,28);//优惠券金额
    & B$ D; s3 V( ~+ ]
  17.                             $id=1;# s' W4 ~* F/ t
  18.                         }
    : |" O/ f+ K9 j; k3 A: h& h
  19.                     }else if($lingqu == 2){
    5 Q) A/ ?2 ~' \
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    9 ~0 ~+ J6 z* R' V8 P3 Q0 U8 A: P
  21.                         if($hours > '17'){
    ! l  _% X' s9 S% ?( Y) Z+ N' A
  22.                             $num=mt_rand(50,55);//优惠券金额
    & n, B. U% s. Y
  23.                             $id=2;( Z1 D7 ?" Y+ t' c0 t
  24.                         }7 v- m$ T$ Z3 H; @8 E2 q
  25.                     }+ \1 k# ]5 b4 p
  26.                     if(!$id){
      \8 r1 L! M4 t. E3 [2 V: A
  27.                         $data['msg']='时间还没到,晚点再来吧。';8 h* C3 L7 _/ D) b
  28.                     }else{
    + f6 B! H$ d/ x0 r' J% z$ q
  29.                         if($is_lingqu){
    ; I- \* k3 K% q# E% R" s
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    , q2 e( Z) n! Z* Y4 Z
  31.                         }else{
    & U$ @: p9 h: `+ G0 T% U
  32.                             //锁表- o/ ?/ F8 X6 y) P6 V3 ]
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');; l) ~% A( c( P. c" e
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();4 d9 \* U# Q0 g* B  F1 f) a
  35.                             if($active > 0){2 t8 ~. S% A& K$ V
  36.                                 //开启事务, D0 Z2 n' A  I6 x( z
  37.                                 M()->execute('start transaction');
    , o9 M) Q. |. i; p* V$ K
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));9 m' {8 v0 m: G( u, V3 P8 K2 S
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));3 X- h0 G2 N+ M" Y
  40.                                 $members_preferential    =    M('members_preferential');
    ! N  [1 a$ v8 {5 Z4 _
  41.                                 //对应投资金额,
    ; E8 m' D# U: r" M
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    4 |5 D- L( M/ E7 ~( G9 J
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');) u' S# a9 _! g6 W% Q3 ~
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    * v  v0 h- @! Z# p' r- J  K
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券2 t# {6 k+ W7 L$ M  x  [
  46.                                 if($save && $add && $add2){
    : {2 X& K0 \: Q0 A1 a8 H' _
  47.                                     //事务提交& t4 _  o  `0 N( J
  48.                                     M()->execute('commit');& o: \9 `5 [. N& t3 P2 S& c
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    ' ~& q& |: B1 q- {$ o
  50.                                 }else{+ q3 d' Y" _  N  _8 Z* }) p  G
  51.                                     //回滚
    , |/ N% W! J" @  N: ~
  52.                                     M()->execute('rollback');
    3 z! h9 x# {% s. a; z3 G2 v
  53.                                     $data['msg']='未知错误!';
    6 r" D/ R, U7 u2 r
  54.                                 }: {: Y. S# n5 u  s+ s- G6 v$ _% M
  55.                             }else{
    8 f& B* z" W# j+ y: V% R8 r
  56.                                 $data['msg']='红包已领完,你来晚了!';) R% [0 T) i* h$ w: F( G
  57.                             }0 W- ~% {. R4 C* Z
  58.                             M()->execute('UNLOCK TABLES');
    ; N2 d  \) N/ m% g5 Z
  59.                         }
    . L; {* w0 g+ N' B
  60.                     }: F' K. b9 K  t: P
  61.                 }else{
    $ h+ U) K7 q7 ^& g2 F( ?
  62.                     $data['msg']='非法操作!';! y& p* [( w; Z! j3 X2 \
  63.                 }
    % i3 }4 s1 A, E9 m0 O! F& K' c% N
  64.             }else{; d: y) e7 D' d) p3 n/ x! a1 a
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    - s* ]' r8 F. w
  66.             }/ a) {# p* V9 c3 _3 i( C
  67.         }
    " u/ |3 r. W; B) F- i% n. p' D! e( {
  68.         exit(json_encode($data));
    $ P; M4 w/ I( B$ j0 U
  69.     }
复制代码
8 b5 U6 P: T# x" V8 M8 A( S4 a

! K, {' @, G' a. [) p, l& x& u9 y
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 17:22 , Processed in 0.049479 second(s), 20 queries .

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