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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3849|回复: 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://请求的脚本
复制代码
- K( q# l) c4 t( [1 k
Mysql中的锁语法:" }' e6 l$ I7 N# g, f) ?
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
$ {8 K/ R1 f' p, u) _2 TUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
$ i6 d9 T. j( F; w+ i7 Z2 YWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
/ b5 l. X; f: V+ Q* [0 w- T# K注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
& J. l7 t3 M$ C) b& b9 o5 K文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
1 J0 T- `9 u& _# f! k测试时,有个文件就行,叫什么名无所谓
总结:( B  g& `# j1 Y' x$ P8 x: U6 `+ b% F
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:, c, B0 b3 Q7 t3 [' P
1. 高并发下单时,减库存量时要加锁
! }. M& W; b; h. B3 p! [1 B2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*6 {/ r) n* R: n4 F
  2.     模拟秒杀活动-- 商品100件
    ) v5 Z  ^. L/ B8 a/ O6 I
  3.     CREATE TABLE ta1 p% E7 c9 `" J0 v6 j$ M
  4.     (( |4 u3 p. F( |. V9 Q3 v: Z
  5.         id int comment '模拟100件活动商品的数量'% k8 z1 n1 J4 Z$ Y1 u2 r7 S
  6.     );) n& G: y# `7 b! h
  7.     INSERT INTO ta VALUES(100);
    0 F% w, O! z! E1 Q# c' z9 w& }
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件% W# j3 C$ f% b& C7 ^  k8 Y- i
  9.      */
    * ~7 k4 I  ^' A9 l5 h3 v. M( X# k
  10.     $ n! s- f9 J2 ^$ D: P+ Y
  11.     // 关闭错误报告1 K$ `9 h: Z1 G+ f: s
  12.      error_reporting(0); 0 `6 S) ~( @: ~

  13. $ [/ M( Z6 m7 X* D
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址, p' O/ ]7 K3 S- `
  15.     $dbuser = 'root';            // mysql用户名
    - R/ u' L* Y' {# K2 d
  16.     $dbpass = 'root';          // mysql用户名密码
    9 e9 G' C9 a- D- S
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);- [9 T1 V. w' L- u. t- L
  18.     if(! $conn ); j% i3 ]: g# i# H; {  A
  19.     {
    8 C1 N7 O3 v9 y( u
  20.         die('连接失败: ' . mysqli_error($conn));
      [0 N+ _7 A( u5 s
  21.     }/ t; U3 [% C. E/ {
  22.     // 设置编码,防止中文乱码( ]  ?1 ]  L7 }5 V% E8 r
  23.     mysqli_query($conn , "set names utf8");, p) r" N. d+ Y: W) t" B$ ^
  24.     mysqli_select_db( $conn, 'temp' );
    7 y  |9 [4 q0 O, D4 u2 Z* @

  25. 0 @! m9 D: T. E: x3 p- z
  26.     # mysql 锁 1 O7 O5 {' V( k6 s+ W
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    ( f5 L; C" ]5 i  E$ F! t* P
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');   h  z# e# p5 G
  29.     $id = mysqli_result($rs, 0, 0);
    7 O) z5 F0 r2 {  O, F4 p
  30.     if($id > 0)
    ) W+ p) u) x' `7 W! l
  31.     {
    3 b4 Z# k6 J3 Z" X! p1 t+ d2 r
  32.         --$id;
    3 @7 p  f# z/ P3 n
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 9 N6 Y' {7 \. `% B0 U
  34.     }
    ; w* a7 n1 o0 K
  35. $ d: Z8 O, ^0 x
  36.     # mysql 解锁 , U' `; s) E2 ~* k- ]# @& X
  37.     mysqli_query($conn , 'UNLOCK TABLES');! a. Y% r% W4 e/ k4 h
  38.     //查询解锁后的id值0 e( y) l# o3 V: k1 m
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    $ v& P# J4 q. a  F% _4 y
  40.     // while($row = mysqli_fetch_assoc($res))) F0 @5 F) |1 T2 A* G
  41.     // {
    : @# n3 B1 R9 T, ?$ a: X
  42.     //     $id = $row['id'];. D$ {! ]$ l+ `  c# U
  43.     // }8 \/ B0 ~8 b. W4 u) ^5 a
  44.     // echo $id;
复制代码
- y1 a3 d0 \+ I2 P2 e; M

! m7 r# S- [% l4 R0 Y
, @4 E7 k$ p5 Y3 r) I/ D) E
PHP文件锁示例:
  1. /*1 J* Z" Z' k8 \. X
  2.     模拟秒杀活动-- 商品100件* l9 m/ y7 I. [
  3.     CREATE TABLE ta
    * p0 d8 d0 G, L0 M1 Y( b( j( c
  4.     (6 x% E) j& N7 ~/ d3 u) q5 i
  5.         id int comment '模拟100件活动商品的数量'+ M# r% B+ l7 l4 V$ v6 _$ k' J1 B
  6.     );
    * r0 j! z" S9 N+ ?# h# m
  7.     INSERT INTO ta VALUES(100);
    # \1 c5 k7 O0 R7 a
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件! K1 f# E: ?  ~* ?& I! K! Y
  9.      */
    ; ~; ]) R- M  J6 p0 ]. x7 k
  10.     . W/ b! v. ^* a% T( q  z
  11.     // 关闭错误报告
    ' A8 R) k1 P- @# j8 k3 Q/ T' [
  12.      error_reporting(0);
    , d0 w! u3 N& `/ Q: v( x* |

  13. ' d, C& B+ q5 w! z5 o
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址; g) [4 k& P! k: L
  15.     $dbuser = 'root';            // mysql用户名0 e0 z7 ]' W. j& j# J
  16.     $dbpass = 'root';          // mysql用户名密码6 l5 M6 p+ S0 A4 E/ b  n
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);0 n6 ^8 U6 h% \6 Y1 u$ O
  18.     if(! $conn )
    1 l, g  F4 M1 j& G+ Y1 e- `% P
  19.     {; u  Q$ Z. ?5 \. Q' M/ f
  20.         die('连接失败: ' . mysqli_error($conn));
    4 A' e$ \: }% K
  21.     }
    : h: I( U( r; v
  22.     // 设置编码,防止中文乱码
    : q+ I. ?! a/ t8 g
  23.     mysqli_query($conn , "set names utf8");
    9 R$ z  m& F# N  z# _
  24.     mysqli_select_db( $conn, 'temp' ); 5 d( M8 f# {( Z4 z+ X. |

  25. ! n1 C4 l6 O" @3 u
  26.     # php中的文件锁
    , M6 h3 M" z$ x* e" Y; `
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 " Z% o/ u+ K. T* ~6 W4 H' z
  28.     flock($fp, LOCK_EX);// 排他锁 * G* t: E9 }6 c8 N
  29. 6 z6 L" y6 L0 q6 [% t* E
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 3 G# i3 p* y2 g6 f3 {" ~
  31.     while($row = mysqli_fetch_assoc($retval))7 K8 Z2 R8 r( Y( n
  32.     {6 Y+ M0 L" \% _3 l! y
  33.         $id =  $row['id'];
    4 S1 V  b( V) x: ^
  34.     }
    , _' x: K& ~: u% R5 ?
  35.     + e" |0 d; w+ b/ a( R/ [1 b$ ]& m) p
  36.     if($id > 0)
    * f; I0 i, |( R6 t$ _
  37.     {
    * z3 s. C6 ^% I' v  ^
  38.         --$id; 2 h! a2 o; q& n0 g& O9 e
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    " m, T2 j& ?( P; |5 E9 t
  40.     }
    & u5 T# s- }8 g; @# b7 B7 F4 I0 ?
  41.     # php的文件锁,释放锁
    ) l8 h/ E9 C% Y/ y
  42.     flock($fp, LOCK_UN); : G8 m" v4 ]7 {. m6 _7 U
  43.     fclose($fp);, S7 f  c9 I) s8 C7 _- `4 y& G- i) G" {; ]
  44. 2 F. {. b# z% j( K
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');7 \7 j0 r$ K4 u
  46.     // while($row = mysqli_fetch_assoc($res))& J9 k) |0 P& M4 `1 S
  47.     // {$ o  ?  e% ^; J2 z
  48.     //     $id = $row['id'];, K8 u' D+ v3 _2 W3 [' X7 P
  49.     // }3 B  Z8 V+ r* g
  50.     // echo $id;
复制代码
8 n8 r4 B) l) W9 A

$ ]6 f3 c: I& P* U( J
抢券活动实例:
  1. public function envelopeSnatching(){
    & H2 a4 y4 i1 A5 X7 y: f( [" T% v
  2.         $lingqu = $_POST['type'];! r  D2 n* Z; w9 U
  3.         $uid=session('u_id');//用户id# m# G' p- r0 Q1 i3 D1 a
  4.         if(!$uid){+ g, j4 w4 p" P, _5 E
  5.             $data['msg']='您没登录,请先登录!';$ v( t8 Q# e7 G! A6 P0 h
  6.         }else if(date('Y-m-d') != '2017-12-12'){: D$ @3 K( |8 Q
  7.             $data['msg']='不在活动时间内!';
    ( y3 p( I* ?- F& h6 x1 H
  8.         }else{. `$ B% p) H6 k( L$ M' |; L
  9.             $hours=date('H');//当前小时数
    / p# g( \6 b7 V' Y8 S5 j* O
  10.             if($hours > '09' || $hours > '17'){
    2 |) u% f& @% O* Z+ a: n8 M  m% b$ {
  11.   b* z, b4 \  v" L
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的. j1 Y) Y+ x  _* o6 c$ q
  13.                     if($lingqu == 1){7 l2 \' ^5 `3 V" P
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过# l" q  D; N/ v. ^4 d
  15.                         if($hours > '09'){
    ' e+ i3 ~; A2 ?- i+ t5 L2 E5 i) R
  16.                             $num=mt_rand(25,28);//优惠券金额. v( I0 J$ l8 z: P" q6 |* @
  17.                             $id=1;
    ' N% y) m- t! {, R4 C
  18.                         }
    - q! e6 x$ V+ ]+ W( z7 T, M' u8 ^
  19.                     }else if($lingqu == 2){
    . U" ]8 c7 m( r( R
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();% A' W/ C. ^4 a6 [, D  O
  21.                         if($hours > '17'){
    ! W$ x' F! ]% p- ]" N: `. }
  22.                             $num=mt_rand(50,55);//优惠券金额
    * b: l$ v) ~/ ^& A+ k) N
  23.                             $id=2;' j. B2 h- e' U. H" Z0 i
  24.                         }; q" ~0 a9 C) [9 l  A
  25.                     }
    8 c* v  q% x; J7 [& y
  26.                     if(!$id){) u+ z2 f. V# G" Z' V4 T5 P
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    ) t/ I% c; w% p' |
  28.                     }else{* a5 J7 n: z* D. `9 }# @
  29.                         if($is_lingqu){+ B6 q- \8 V6 `/ q) q9 d3 |
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    % Y6 c1 R) j8 e0 A
  31.                         }else{
    $ [: L; p- ?, n3 L
  32.                             //锁表" N9 r! Z: k1 s
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    " O% u( w/ m8 @+ o
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();9 _$ r# Y0 F+ D  V2 |, y2 Q
  35.                             if($active > 0){
    : l* k/ c  B0 i# j5 E6 l
  36.                                 //开启事务- |( _4 {3 h% G. i: i
  37.                                 M()->execute('start transaction');% Z/ F; i: i% G8 t' L
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));# d! a% `6 G+ }! I& a& T7 R  S
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));6 p# Q# ^* b) R) I0 l+ F+ L
  40.                                 $members_preferential    =    M('members_preferential');. ?( @: T2 k/ k* M9 H$ {
  41.                                 //对应投资金额,
    ; [5 g8 B( k; {% X/ h! w
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ) H$ u6 v) \1 p  O' g: r9 p
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');! a8 I# y4 G; V8 c  L4 o. ]
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间# m' A) b6 e" H9 O1 q
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券6 A8 H5 L; W) ]$ M/ X
  46.                                 if($save && $add && $add2){
    4 k  y4 |) l8 q& L' @/ j
  47.                                     //事务提交# K& y: q5 [0 q2 C6 R) m: K) N
  48.                                     M()->execute('commit');
    : }* Z, d" J1 T+ |; ^
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    ( R) C0 x0 i- ~' L8 g; V. [6 V( r
  50.                                 }else{
    ! p+ K# a# f: n1 R8 `, l: l7 F
  51.                                     //回滚# a: i7 B( V/ w' |
  52.                                     M()->execute('rollback');
    ) u  P' W) D- H. p+ t9 n) J
  53.                                     $data['msg']='未知错误!';: j1 }* {* ^% i$ g" V0 I
  54.                                 }
    ; t, c1 [' p. X$ ]6 u# W
  55.                             }else{
    4 J$ E$ t1 G5 I# x1 N' m/ y
  56.                                 $data['msg']='红包已领完,你来晚了!';
    # N/ B" r4 y7 D8 R2 T3 P
  57.                             }. L  |# }4 w9 P+ [2 e
  58.                             M()->execute('UNLOCK TABLES');$ m2 l" e% Z$ ]
  59.                         }2 E0 s# O0 E. a! h) I, P
  60.                     }
    0 F& y, D+ u- d/ V; X- O! H" e
  61.                 }else{' f3 G. @' F0 v: u& f5 b) G2 G
  62.                     $data['msg']='非法操作!';4 {& q9 E& V& i2 ^
  63.                 }; f! c+ H" [: Y1 P9 v$ {
  64.             }else{2 R, s5 y$ M: K/ V* K& Q$ E( v
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ( R( X1 k; _  Y+ _6 G* P
  66.             }
    % q8 A, u+ j/ s7 _% ~
  67.         }
    . ?0 A' Y) e, Y4 Y
  68.         exit(json_encode($data));
    / K  v6 f8 F1 p6 i1 B
  69.     }
复制代码
( D4 T+ e+ z" T
' V! ~. Q4 z5 G0 q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-7 14:09 , Processed in 0.158655 second(s), 22 queries .

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