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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8204|回复: 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://请求的脚本
复制代码
; x; b# L6 @) E. O6 p5 W' q
Mysql中的锁语法:$ x; Q# U5 t( j, I, K) O, Q
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】  d) p4 e3 _  [' y
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表2 [- Y: V( [* N5 D
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
1 D1 I+ \9 U+ G6 ~* W; z+ z注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
) k+ e7 X: J, h" Y: e& z/ u文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。0 V6 F9 g  F( q5 X# f2 T/ |6 @4 b9 O
测试时,有个文件就行,叫什么名无所谓
总结:, l, v) E5 M# ^! ~
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:& p, x7 b4 z* F3 S, Y. q
1. 高并发下单时,减库存量时要加锁
  ^! D3 P6 a( F% j1 m  H- [2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    - @3 _3 R& A8 o
  2.     模拟秒杀活动-- 商品100件
    . s% |  X" m5 h+ G
  3.     CREATE TABLE ta
      Y/ a# o; @2 B% ]0 `
  4.     (
    * [1 w& v5 V- f- a
  5.         id int comment '模拟100件活动商品的数量'
    0 Y; ~) n3 n4 W9 H
  6.     );. O' X9 ?& m* ]: l* \' J
  7.     INSERT INTO ta VALUES(100);6 ]  }- L$ H; S
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件& |) Z8 N' {* ]- P& b+ Z) C- |) Y
  9.      */ ! Y% P  k$ ]) Z
  10.     , Q1 E) p8 Y$ ?
  11.     // 关闭错误报告
    ( s2 ^$ P' W2 H- ~' i
  12.      error_reporting(0); ) ]" _$ q4 R8 U, K% ?

  13. ( r# H: |2 s, t2 j$ O/ @( E
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* T) x) Y5 S- m
  15.     $dbuser = 'root';            // mysql用户名
    : i9 F( ?; h& l1 v
  16.     $dbpass = 'root';          // mysql用户名密码
    1 ]% X" r' t$ a; W7 Q
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);. i( t2 o1 O+ @& w4 Z
  18.     if(! $conn )
    + r! w% f- C) F
  19.     {1 K0 R8 ^+ b$ C5 k; v5 ]
  20.         die('连接失败: ' . mysqli_error($conn));! |: w' G  F" }3 B! A
  21.     }! d7 g4 b! v$ w4 C( y
  22.     // 设置编码,防止中文乱码
    4 W$ N( m* u- Z. b  r( Y
  23.     mysqli_query($conn , "set names utf8");, q1 n$ W9 S( A& S: q9 N
  24.     mysqli_select_db( $conn, 'temp' ); # K5 G/ D& F/ {# A; E

  25. : o, p: ^* }% r$ J9 [, q
  26.     # mysql 锁
    1 }  q& R# w6 q
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    . R1 V; S- F4 l8 e+ I- c
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    # i% C$ u, f) [" t& h& t- B% Z, ^4 _
  29.     $id = mysqli_result($rs, 0, 0);
    + [* @! H+ W* W2 `7 J0 O- ~
  30.     if($id > 0)
    # a2 Y, {* P$ a
  31.     {
    % G0 \: Y5 Q  f
  32.         --$id; 8 C* s# V. y" g5 \. \8 k9 L+ c4 t: y/ ~
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    : A4 S8 q, e) M% n
  34.     }
    5 U! k/ F2 f8 ~/ W
  35. 0 [5 n8 s% J" ]! S2 J! a! |
  36.     # mysql 解锁
    . a, W3 d5 Z8 A' o
  37.     mysqli_query($conn , 'UNLOCK TABLES');8 \. ]. w& |+ d& {
  38.     //查询解锁后的id值/ l" U3 m% o. _! s, i% I# a
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    . m' i1 v2 R, o  W7 q2 N2 L
  40.     // while($row = mysqli_fetch_assoc($res))
    + p/ X& A' }, i' W' F6 t
  41.     // {
    9 T+ C% Z# w  C1 y* O- a) ?4 c
  42.     //     $id = $row['id'];
      G2 g' v8 V! z3 Y& W% b  ?
  43.     // }
    : o9 s; q$ V" B7 A7 }  _% D0 l4 B
  44.     // echo $id;
复制代码
) L4 @, U, N# j8 ^
3 L' w1 Y/ Q# K% j$ E2 I
! K: b" U7 c# s1 R; ]
PHP文件锁示例:
  1. /*
    / x# V5 u& s; c: C! _& Y# n+ \
  2.     模拟秒杀活动-- 商品100件
    ; Z5 u) P8 _$ k
  3.     CREATE TABLE ta
    : `- {, q3 H; g$ \; J0 `0 {
  4.     (. y3 }+ h8 N2 p  A5 b( M$ q
  5.         id int comment '模拟100件活动商品的数量'
    $ G6 G( z7 |3 R" R9 `
  6.     );! |/ |1 u8 C: r5 K2 ^
  7.     INSERT INTO ta VALUES(100);
    7 S$ U" ^, x' b' z
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    3 Q% ?/ K# R: @9 `7 O
  9.      */ 0 y0 `5 ^6 }: G( K  P4 L
  10.     - L, x! Q0 r4 I6 t. t
  11.     // 关闭错误报告
    # p  ~1 G& L, R; W' I
  12.      error_reporting(0); . ]/ v8 y$ r0 v' t' {

  13. ( W  _/ J' {+ U7 n
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    : f% s8 |# ^* v! f' ?, r
  15.     $dbuser = 'root';            // mysql用户名' `3 ?9 u  q" v/ Y
  16.     $dbpass = 'root';          // mysql用户名密码
    7 J  C7 U. ]7 D
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);. I% P; d) l2 i7 W" d
  18.     if(! $conn )
    3 A* O# R; L/ h% ^
  19.     {, g8 l# Q1 f- B9 M
  20.         die('连接失败: ' . mysqli_error($conn));9 R, _; s/ s. i/ g5 C& K! {0 K
  21.     }
    ) ~/ O/ m" a/ a- P1 M6 M: g8 S8 u
  22.     // 设置编码,防止中文乱码+ @% C0 d9 A* N/ {
  23.     mysqli_query($conn , "set names utf8");
      H- O% k- R, b3 z, |
  24.     mysqli_select_db( $conn, 'temp' ); 4 n. x' z* \4 B8 a

  25. 8 P# k( v3 K6 ^$ s5 d  X! J' i
  26.     # php中的文件锁
    8 V, ]6 R& V: ^* S
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    1 \5 @7 |+ c- i
  28.     flock($fp, LOCK_EX);// 排他锁 % V9 a$ J7 d) O1 s0 b

  29. 8 X5 ]3 ~# K$ L
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    - _' x0 f( s) Z: \
  31.     while($row = mysqli_fetch_assoc($retval))
    5 G# @# w, _2 O' D2 u. K6 c; U
  32.     {5 L- X4 f' R; n8 _- H
  33.         $id =  $row['id'];
    2 @. I* y8 a; Y3 u+ m
  34.     }
    * x% m$ F% k1 n
  35.     9 y4 ?8 s, W: B1 f3 L1 \& e
  36.     if($id > 0) - T- f" q0 |# t5 p3 E2 {
  37.     { ' u7 L" o+ d" i8 C4 o. |$ c! d
  38.         --$id;
    * A* d1 n/ S5 E) g# Q2 k
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); , d$ l4 p2 l  S, ^  a
  40.     }
    - N: I! h8 Q9 A1 D
  41.     # php的文件锁,释放锁
    ( _9 k9 A. \0 r% {! |6 J! k" \; N2 e/ ]: Y
  42.     flock($fp, LOCK_UN);
    - v/ T# T) m5 \" a. h' \/ U
  43.     fclose($fp);
    + R+ [8 \9 ]" I

  44. , f: o1 |! M' L% H* b. a6 F( G) b
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ; i4 |& O% t0 u' W+ P4 ^
  46.     // while($row = mysqli_fetch_assoc($res))! M0 E2 {$ `3 \
  47.     // {
    9 z8 c) M8 t# B- l( Z
  48.     //     $id = $row['id'];
    * B" |- J% A% C; \- B4 E9 r
  49.     // }1 p6 [1 T7 [0 \7 {
  50.     // echo $id;
复制代码

& _, g+ e# o2 n& k! L: S$ d- r5 }/ T0 W9 I, ^
抢券活动实例:
  1. public function envelopeSnatching(){
    9 y$ g. E4 O. c8 _# C1 s" A
  2.         $lingqu = $_POST['type'];
    1 c/ F2 H. F$ S3 w$ J9 n8 {
  3.         $uid=session('u_id');//用户id
    * e, T* h2 }( ~9 T( h
  4.         if(!$uid){6 ^* w1 P2 f0 d$ a
  5.             $data['msg']='您没登录,请先登录!';% q4 U# A+ p. `
  6.         }else if(date('Y-m-d') != '2017-12-12'){6 S& h% C$ l1 T/ g" H
  7.             $data['msg']='不在活动时间内!';
    3 a7 l) i; q3 w7 j
  8.         }else{
    , U1 Y+ n5 }) B/ Y
  9.             $hours=date('H');//当前小时数
    3 v. E! c. E0 W# \* A9 x
  10.             if($hours > '09' || $hours > '17'){6 S8 X2 `1 L1 P# P7 O% e
  11. 5 y- ], M* e, F( B6 V
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    ; ^- M) ^  f) K5 r$ p
  13.                     if($lingqu == 1){
    3 N) B$ g) d3 T
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    4 R! X9 `% {. k# z
  15.                         if($hours > '09'){
    " _0 [* s5 W; p. }
  16.                             $num=mt_rand(25,28);//优惠券金额
    . |$ J; k3 @& R4 D9 a( v, n
  17.                             $id=1;' B( @" g: u9 ]; V
  18.                         }" L  S( i( T5 P9 K/ N7 S
  19.                     }else if($lingqu == 2){
    - A* k8 U8 u. T9 V: e: \
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();! b/ Y. Z( G( F* Y, f' X
  21.                         if($hours > '17'){. L$ Q' _: ?8 O' h) k2 {
  22.                             $num=mt_rand(50,55);//优惠券金额( x2 j4 f; n" y- O  [
  23.                             $id=2;* i. @) y- P2 {. A8 W* G- j/ l
  24.                         }
    . l3 q9 b+ h$ F  s: x+ W  ]
  25.                     }
    " A( e: K! V$ \2 m" [2 m0 M
  26.                     if(!$id){/ t2 l$ {- D6 Y* g; y
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    . Z, R# |# f- i7 y
  28.                     }else{1 n* p; P2 }  t) w' L5 \( O+ `
  29.                         if($is_lingqu){" F! t9 x; L4 Y
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    % F1 A. q: R/ O# n% H2 p
  31.                         }else{
    ( c  ?# N0 ]; ~# j$ C; c
  32.                             //锁表* [" J$ d/ F7 e' a( |' L( s/ F* H% q
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    9 y: b' C- X4 y0 L$ t
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();) q. G* a$ L7 d, J1 v
  35.                             if($active > 0){
    2 y' B) @; t8 F
  36.                                 //开启事务
    ' ~9 ]3 S& z) C" A% S1 r7 r
  37.                                 M()->execute('start transaction');" K; C- J, X) F5 \) w' s
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    7 u, U& A: V% a7 |* ]3 y' N
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    # W7 K4 _0 s/ P3 b( Q& F) ^
  40.                                 $members_preferential    =    M('members_preferential');
    , E- m/ x8 W: ?5 s9 y! Z9 K. z- m
  41.                                 //对应投资金额,
    " P6 F2 l% {+ t
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));. {1 g' t# ]4 m9 O3 C
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    ; F0 L/ e$ F4 _* s2 y
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间6 T/ k$ n+ g" n# ^; _! e8 n; T
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ; H: L2 b9 V* D+ T
  46.                                 if($save && $add && $add2){
    ' z* U- z0 a9 m3 F- D% z) v
  47.                                     //事务提交
      w, Z0 r1 k! ^7 T, R# f& N) j
  48.                                     M()->execute('commit');. X6 \2 ]6 ^8 F. i0 v7 V  \
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';2 t0 a- m. v: S
  50.                                 }else{
    5 g- C7 s/ v, H# S: U. \
  51.                                     //回滚
    % d# U8 e6 G9 s4 B3 r- |; O( A6 @
  52.                                     M()->execute('rollback');+ e3 M; @+ }) h$ b; |2 W! N3 \
  53.                                     $data['msg']='未知错误!';
    * a7 m* X. @1 p3 f0 D
  54.                                 }& C  y1 W8 I! [2 f) l* h
  55.                             }else{
    % X' M/ t% b  V3 U- c# Q& j! Q4 ~/ q
  56.                                 $data['msg']='红包已领完,你来晚了!';# d7 X+ {2 w2 \% o( f# g
  57.                             }
      A& V9 k; x. n' y9 @3 W8 k
  58.                             M()->execute('UNLOCK TABLES');( a4 |6 o, K- h! [* D
  59.                         }
    ( \  C$ k3 G  Q3 _, \
  60.                     }
    ( G$ ~+ N3 p. ^% Q8 H
  61.                 }else{; M0 w8 A( h% M+ b
  62.                     $data['msg']='非法操作!';6 p0 r$ e8 L& Z7 \5 b
  63.                 }8 V8 B+ e% t5 {& s4 ]: T& a; T
  64.             }else{+ P/ f: ~* Z" v  A0 D" Y: a
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';+ k5 K, \" w7 P: B
  66.             }
    ( F" q3 M8 ^5 x1 O
  67.         }
    8 _& N6 O9 ~; Q+ I& @
  68.         exit(json_encode($data));: ]. J$ ?- m+ C5 L1 w: W
  69.     }
复制代码
9 U. N! d9 Q9 a9 e

% w  ~! U4 {7 I7 R- V( S
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 08:11 , Processed in 0.051371 second(s), 19 queries .

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