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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8211|回复: 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* e" U" Y9 g
Mysql中的锁语法:8 s4 o* R9 H- t1 b2 A& k. j
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】: i! z& v4 [3 O" G, {  j! @; i
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
4 R3 z% s  h7 a9 l5 yWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
8 d1 J7 S: D- ^2 U% j8 l- M( h注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
; Y" ?4 f. [3 y: V3 g文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。& _0 o7 U' q( I! v
测试时,有个文件就行,叫什么名无所谓
总结:4 x7 ~9 e& I: Y5 R0 {3 {8 S
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:; p$ N7 n1 s! i- f8 c( n8 T
1. 高并发下单时,减库存量时要加锁
0 M9 }- A1 [2 E  ~2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*& U' v& D: @; p$ M7 M! I
  2.     模拟秒杀活动-- 商品100件9 c+ G7 _4 a: g. B5 U% q
  3.     CREATE TABLE ta
    2 L  F! K/ V' e* |9 D3 e% o
  4.     (
    . z. t& e3 _# s, L+ W( m
  5.         id int comment '模拟100件活动商品的数量'
    : W& ~8 P* p% j5 T
  6.     );
    8 L: S! [& d' Y' P  r7 i
  7.     INSERT INTO ta VALUES(100);
    5 Y7 I% u, w: U! r
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    6 `" {3 N7 ^. v* J0 V5 m1 F- ?' _
  9.      */ " o/ k* l' v  ]1 G: C. b: X. @
  10.     " ?" @4 {+ \: e2 a4 I; X
  11.     // 关闭错误报告
    + y" A" o( |7 K
  12.      error_reporting(0);
    1 f# D* q/ [+ ^5 `6 \1 [
  13. 3 u9 y4 |7 w: T5 b
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* K: q0 i- e/ [5 a" J
  15.     $dbuser = 'root';            // mysql用户名/ ~) [$ Y8 B( M
  16.     $dbpass = 'root';          // mysql用户名密码! L% t! g) s( K6 @6 H6 w
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);; D3 l" l6 b! L& H2 `# l, A. g- @
  18.     if(! $conn )
    ) y. x' x9 n. b9 n' q& S# ]
  19.     {/ e! B  r2 a5 \0 ?
  20.         die('连接失败: ' . mysqli_error($conn));
    9 `. e' h; n# m6 R% N
  21.     }3 g; j' e& e; |, f8 X0 x
  22.     // 设置编码,防止中文乱码: V: `  f% a$ M+ v+ b% S. _
  23.     mysqli_query($conn , "set names utf8");
    4 c9 o3 z8 W. ~
  24.     mysqli_select_db( $conn, 'temp' ); 4 {9 v% P& m- a1 J$ [; B) u

  25. $ j5 S! e0 G# T
  26.     # mysql 锁
    9 }' Z  X- d0 K" ^5 I
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    7 B5 R# W( Y5 K9 [& R; `
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    : g4 b; J/ e) L
  29.     $id = mysqli_result($rs, 0, 0);
    / K# H8 j6 F& W$ B0 v, x* s1 R3 j& o
  30.     if($id > 0) 8 ?: `8 [9 o; w! W  [( L( z
  31.     { " J+ G6 K  C% U1 @3 a
  32.         --$id; / J9 p7 ~, Z3 \1 U& @) ^1 Z
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    " N5 x9 J* P& k3 H/ O
  34.     } ' H) }7 p. F( y# W7 Y1 l5 Z) W) T
  35. 2 S7 N7 {% G5 p; p- J
  36.     # mysql 解锁
    : G3 z& m) A9 X' `4 T# g
  37.     mysqli_query($conn , 'UNLOCK TABLES');  U. a( Z0 N8 ^6 H+ _" e
  38.     //查询解锁后的id值/ Y4 z6 `2 E" H& ^# [% B
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    8 `" Z5 b  i( r0 v
  40.     // while($row = mysqli_fetch_assoc($res))- _; C' ?4 m! E- |. s( Q$ z9 B7 G
  41.     // {+ j& z. h9 s/ I
  42.     //     $id = $row['id'];
    8 {/ f1 h5 W/ y/ M3 G  J
  43.     // }
    : I, V4 M$ l7 J! J
  44.     // echo $id;
复制代码

5 |$ i/ Y0 P5 m9 C+ ]
8 K7 z& Y' ^1 N% n" V, N. j& h

* I- w# s) L( h9 h2 T  ~
PHP文件锁示例:
  1. /*
    + ~9 y2 E. T. z, j
  2.     模拟秒杀活动-- 商品100件
    $ S8 G% g2 V% X5 T  _2 t
  3.     CREATE TABLE ta! C7 z+ X9 M8 |' v3 w( L0 l
  4.     (" ?# @8 K" n. D( {
  5.         id int comment '模拟100件活动商品的数量'
    + V5 u$ b" S0 f
  6.     );7 P; a+ o, w7 c2 |. k4 X# D; z: M
  7.     INSERT INTO ta VALUES(100);; \% V4 u8 W% n6 y0 p' b, z
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件- a1 t( O8 H/ H8 j
  9.      */
    - @# {5 ]" }3 T. F6 m' w: b
  10.    
    0 A0 Z# w, a4 h; T, C
  11.     // 关闭错误报告0 b* e+ c. p' L  b" N2 g* ~2 W
  12.      error_reporting(0);
    8 J4 k( q1 x( Z3 N7 ?

  13. 6 C  A, D2 N3 [+ m' ~
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址6 B! b; H; R; d8 x1 ?6 s. W; j0 [: d
  15.     $dbuser = 'root';            // mysql用户名
    / V; a" a( ]4 [( s5 ?
  16.     $dbpass = 'root';          // mysql用户名密码6 C# H* y  N" e
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);1 W! l6 p8 A  e8 z+ @; d
  18.     if(! $conn )# W+ q( B* R! \3 N2 }2 g
  19.     {
    9 }, i* ~* ^0 u" @3 [' `3 j
  20.         die('连接失败: ' . mysqli_error($conn));
    " a: {% e/ |, o, H2 y) O9 O4 ^( c' ?% S
  21.     }2 B7 ?& [& m1 m- {8 R+ X6 _$ @: |
  22.     // 设置编码,防止中文乱码" e  D8 `+ V: W8 p
  23.     mysqli_query($conn , "set names utf8");: v' ]+ I5 l0 K2 K9 i  [/ Z; Z
  24.     mysqli_select_db( $conn, 'temp' ); . R; ~2 Z1 v5 i& O8 J* o
  25. 9 U0 ?" [. u7 O) u0 F( a5 p# g
  26.     # php中的文件锁 1 L, i1 s8 ^) u$ o( E
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    / ~3 T+ F  k- R+ h
  28.     flock($fp, LOCK_EX);// 排他锁
    : q/ y* L. ]* I' j5 q7 h6 e

  29. : V4 Z; z& [; b0 ~4 K% t
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); + I! [0 a  ~( I& `2 ]
  31.     while($row = mysqli_fetch_assoc($retval))* \4 r, A3 [" @- P  m& d* s
  32.     {" }+ c/ o- [% O* [; A
  33.         $id =  $row['id'];% V5 L" [3 L5 G1 \
  34.     }6 w% E' q* V  s6 F; ~$ s* _
  35.     , P" M' Y6 T% ^% O: I+ N1 g3 e. t
  36.     if($id > 0)
    , a% H: q; g/ f; K
  37.     {
      _( d& x% b2 C& q; ?
  38.         --$id; 7 u/ q( J5 n$ @/ M  V
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 7 b5 k5 L+ [; e4 q6 v* U: X/ {
  40.     }
    9 ?' O. R! X8 ~2 I# N5 ^
  41.     # php的文件锁,释放锁
    0 E) i0 }* r* V1 _( t! [
  42.     flock($fp, LOCK_UN); : c- D9 l4 z+ c, Q$ U5 t
  43.     fclose($fp);
    % Q' A8 i( w* x: a
  44. + L3 g$ G; h, B/ [  [) c4 f, n- w
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    5 k1 v+ }. Y9 f
  46.     // while($row = mysqli_fetch_assoc($res)). k/ E7 }' n1 _& A2 o( ~
  47.     // {- l5 {0 `3 p9 c% e0 J  s: w  p
  48.     //     $id = $row['id'];
    - x2 y1 P/ t; N  }  U: o' U1 K
  49.     // }
    1 f4 V/ q0 ~! f: @! O: F
  50.     // echo $id;
复制代码
6 ~' w1 V7 M" X! N8 j

* L$ H  J# u# H- P* P0 O; p
抢券活动实例:
  1. public function envelopeSnatching(){
    # C9 x% D& p- f/ N
  2.         $lingqu = $_POST['type'];
    7 p/ I$ a: u2 @5 @8 [, B! c
  3.         $uid=session('u_id');//用户id
    . M% \2 C$ o5 b3 k) i: {! A* q
  4.         if(!$uid){
    % \/ h+ K# {; q! m1 P5 H
  5.             $data['msg']='您没登录,请先登录!';
    # K) D+ Q2 f3 w- R4 A1 j
  6.         }else if(date('Y-m-d') != '2017-12-12'){# {; f) G7 G- \
  7.             $data['msg']='不在活动时间内!';
    % ^8 l; @: s2 u. U+ S
  8.         }else{
    - y5 R& F6 [( `8 M+ K/ A
  9.             $hours=date('H');//当前小时数
    5 n3 v0 G' ]# h- {
  10.             if($hours > '09' || $hours > '17'){- K1 M1 B, W* C4 K' p' ?
  11. ; O" J- F# f) n. m; `1 M
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    & q3 S8 b; X" J! ]/ F  J6 B: F
  13.                     if($lingqu == 1){3 w0 b/ U! `* |2 B# h. P8 J6 r
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过& d, m; U- ~3 Q' \0 E
  15.                         if($hours > '09'){  F/ K" i) h( ^$ t
  16.                             $num=mt_rand(25,28);//优惠券金额
    2 ~0 ~& S" E' D6 R% U
  17.                             $id=1;2 |) ^, w; E* h5 K
  18.                         }5 _3 _% t% |- Y  r- v
  19.                     }else if($lingqu == 2){2 ?" d0 _3 q' N) o& i* ]
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    0 {9 j3 A& v/ E1 ~8 {
  21.                         if($hours > '17'){  c5 M1 w: b8 K3 }, [1 J; m
  22.                             $num=mt_rand(50,55);//优惠券金额
    ! G% X0 l# F8 }/ y8 ?. H
  23.                             $id=2;1 a% q" k' a  X# p9 P
  24.                         }1 F" J% U# v( \; d
  25.                     }
    9 A! a% y# A/ u+ `, d4 p
  26.                     if(!$id){
      |) i2 }4 w1 w  `7 K; O
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    . ?" G: |' l5 _
  28.                     }else{# I5 Y; w0 f0 H5 A
  29.                         if($is_lingqu){! v7 Y, v. c( |1 u& D4 i* R$ r$ i
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';6 @/ |6 `1 Q+ P4 S9 w
  31.                         }else{5 d+ M, i% u% E. V7 u
  32.                             //锁表" z  s  O  {1 n9 e
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    # Z. o9 d+ q6 T5 a" a
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    7 t9 }7 |( h. i& {/ j) i; A5 }
  35.                             if($active > 0){; B# a5 M2 w4 i! X4 O8 X& z, [
  36.                                 //开启事务0 p0 S# M) K1 ~
  37.                                 M()->execute('start transaction');
    9 e1 o/ i' c& `9 t
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    5 U! \+ {) D; d1 R
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    . B" |0 B2 v/ e9 @
  40.                                 $members_preferential    =    M('members_preferential');, t# S8 y+ X9 ~; W- s5 u. |
  41.                                 //对应投资金额,7 _0 C$ L8 r& [" V
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));, d  Z$ |" d! A
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');4 k5 U. C8 o5 L$ M( J
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间% B0 f0 u8 v$ j- h2 k
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券- I" q* f, y- d
  46.                                 if($save && $add && $add2){
    ' i4 j% x" o/ C5 {
  47.                                     //事务提交
    : D: d7 K9 U8 c1 I7 u
  48.                                     M()->execute('commit');
    8 W: h% ^# y" O) R) I* H+ ^
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';3 V8 r  O! K* N; ]
  50.                                 }else{
    " q- ~* l- V) r! z) c  P
  51.                                     //回滚: |5 H6 Y3 b0 w- o7 l* \
  52.                                     M()->execute('rollback');9 p: X+ G9 ^5 l; X5 [1 k. n
  53.                                     $data['msg']='未知错误!';0 q8 e3 \3 U0 o) @* I, z& n' h8 d
  54.                                 }
    ) z7 j" }7 e6 r' F1 [  n& G9 I/ R+ {
  55.                             }else{
    + @' u/ [( `5 I! _
  56.                                 $data['msg']='红包已领完,你来晚了!';# `$ m+ y- `5 l. C9 c+ M
  57.                             }
    - ^  i/ z  Y/ m. X9 n9 k, d$ v
  58.                             M()->execute('UNLOCK TABLES');3 x4 O, z$ j& d; `) x$ n' [+ }
  59.                         }$ c) r: q7 t- ^9 H
  60.                     }2 ~: r6 m' ]8 d( a
  61.                 }else{
    ( |& i8 S5 R# v
  62.                     $data['msg']='非法操作!';% P/ A2 h, N+ {
  63.                 }
    4 D/ E4 N% m9 b; D" S8 l5 {
  64.             }else{
    ; @. O4 _" p5 ]* B" W( B% x! s1 t; C
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    : I5 k# R+ P' u% L' x) t
  66.             }( k8 e. H0 L; ?+ E
  67.         }
    0 |3 m. m. b5 h3 b$ l
  68.         exit(json_encode($data));
    8 Y  M3 s+ _6 w
  69.     }
复制代码
' |3 T* W9 D  ^/ V& h% @
  W8 O8 v4 X+ J4 K9 W7 z
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 14:31 , Processed in 0.053275 second(s), 19 queries .

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