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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 5740|回复: 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://请求的脚本
复制代码
$ i2 v* E/ c: W% X  q! H2 h
Mysql中的锁语法:+ O6 A9 N" s- d
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
, P1 h+ \! X/ Z2 V0 UUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
, X6 Q% r* Q; z0 T2 s! e7 ?5 r$ eWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞& ~/ V' e" h1 [
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :% B4 g8 F) s, Q9 a+ `6 |  f
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
; W8 L; m3 j) T$ x8 w测试时,有个文件就行,叫什么名无所谓
总结:
" x' p* z% Q* P  R项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
0 R# y& d# X& w6 z9 u6 [1. 高并发下单时,减库存量时要加锁; U! K: g- r5 Q- M, y1 s8 P: R
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*$ v7 h: Y& H" Z$ [
  2.     模拟秒杀活动-- 商品100件
    / l' s1 d" [9 s& k  G* f5 F7 f: ]
  3.     CREATE TABLE ta
    8 q7 i# l3 O; ^
  4.     (' A+ q5 n5 Y7 E# S7 ^
  5.         id int comment '模拟100件活动商品的数量'* x5 I; Q  v& L& g) ?3 n0 R
  6.     );
    2 y) M0 n" p8 U1 O' U. M
  7.     INSERT INTO ta VALUES(100);) I4 d2 g) b/ E  Y
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件( Q' V# e! {3 t8 a) j
  9.      */
    4 T* a2 u: O; X# Q  u
  10.    
    9 \6 A- o, O. m7 H/ Q" h! ^
  11.     // 关闭错误报告& H+ x* Q0 N, }7 h  B
  12.      error_reporting(0);
    0 B+ b: P7 H8 h6 g" {
  13. & j& _! q) a" }
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址9 s/ O+ N1 w% w, e
  15.     $dbuser = 'root';            // mysql用户名3 r) _9 i/ }' L. K
  16.     $dbpass = 'root';          // mysql用户名密码$ [8 _* V! s. ?5 k5 E
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    - h/ @& h/ e5 z
  18.     if(! $conn )8 x" V& l9 L  A- G- X
  19.     {1 D" D& S5 \4 l6 _! U, C2 I
  20.         die('连接失败: ' . mysqli_error($conn));
    , W: a- A& O8 c9 g
  21.     }
    + A0 r/ [5 R1 K& e2 x9 y8 z
  22.     // 设置编码,防止中文乱码
    8 {0 \' F/ C& n9 M  T8 j  W
  23.     mysqli_query($conn , "set names utf8");
    * r, u/ E) j  e8 T& S! ~( u8 u/ }
  24.     mysqli_select_db( $conn, 'temp' );
    / G. X) B( _# n( K& v/ {
  25. 0 f+ k' [( N9 _- o4 Q# {0 w+ T
  26.     # mysql 锁
    1 Q0 `; `+ V& w# v. z) u
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 & N$ ?) o# g! X8 m# y8 [) e
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); ) j6 `4 x5 Q/ \" o8 @9 K
  29.     $id = mysqli_result($rs, 0, 0); & n8 Q/ P; B- H
  30.     if($id > 0)   f* y( y  e' o! m& t& g" ~: u
  31.     { 9 J. g. Z' h( S: r
  32.         --$id; ; u8 {  p0 z) X1 ]. P8 A, R
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    1 i( }6 u- d( r! e4 j* H
  34.     }
    3 a+ O4 R$ p2 k$ l0 O+ _; V

  35. " W/ G0 T+ Y' h0 E7 W" N
  36.     # mysql 解锁
    8 ]/ v$ L. i7 E1 h' B) I, U
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ; i, \3 ~8 W! L/ D" t: n3 T
  38.     //查询解锁后的id值
    % y4 X$ Z; N) c( _( E
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    1 ], c4 S. E) P* a6 F
  40.     // while($row = mysqli_fetch_assoc($res))
    # M1 S. J! P5 x5 [: i
  41.     // {% J9 _4 K1 c& I8 D& ^" `: G3 ?. E' d
  42.     //     $id = $row['id'];
    5 L: I* e0 f. |0 Q2 V/ W* K
  43.     // }
    / W" x4 u" C4 l
  44.     // echo $id;
复制代码
/ z9 K9 M# O1 \. \! g9 c
& D, r6 j5 R0 U5 m
9 B3 _! f! E8 Y' K: V4 z% v0 V
PHP文件锁示例:
  1. /*9 L: X) B8 X% |- b- M2 O: P
  2.     模拟秒杀活动-- 商品100件, m. c" p9 A, J& ]' y  E
  3.     CREATE TABLE ta) W/ s( N0 X3 Q5 n9 B8 f- g
  4.     (
    * W- H0 U# E1 }2 S$ U
  5.         id int comment '模拟100件活动商品的数量'$ L* x  M$ G  E6 B
  6.     );) u- P( a  A' p1 c8 }
  7.     INSERT INTO ta VALUES(100);  X' ^! @% d7 j3 a2 Q
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件3 M& L( o) l8 J2 l
  9.      */
    3 }- ?8 K% y5 B1 f" y7 g1 A0 g9 r9 H9 O
  10.     & [9 T! R* i" O2 x$ |
  11.     // 关闭错误报告! S9 i; x2 a! ^* q! Z$ F
  12.      error_reporting(0); & I+ k" ?( B( s2 O7 f
  13.   f% {1 P9 h4 B+ l; Y: X" y) [3 V( c
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址6 P+ J/ Z# d; b3 M; Z6 v0 @. U
  15.     $dbuser = 'root';            // mysql用户名
    + j' J2 ]0 Q9 F$ g) y4 t
  16.     $dbpass = 'root';          // mysql用户名密码
    / k" G: A+ q' |3 h
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    4 ]& B6 Z. X7 n7 x: I3 }% z" z
  18.     if(! $conn ): H* K) q  N% k4 F2 K
  19.     {
    ! ^  N' t1 J( C
  20.         die('连接失败: ' . mysqli_error($conn));: q; C' V1 |$ e9 a0 H# h. @. s
  21.     }
    & h& O1 r. b$ N- R; r, g
  22.     // 设置编码,防止中文乱码# E; T4 B+ `# J6 W* x/ J) j8 ^
  23.     mysqli_query($conn , "set names utf8");
    / y4 T9 s3 g* d( ?7 v  g
  24.     mysqli_select_db( $conn, 'temp' ); & m/ I; ?+ b# G  r2 Y
  25. 2 E7 G5 ]- U. K5 J, R
  26.     # php中的文件锁
    3 q5 }* D1 {2 E/ o& @/ P
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    $ Q' B. k- [8 _- k" T
  28.     flock($fp, LOCK_EX);// 排他锁
    5 g* Y* @7 q% k7 Y  Q* x

  29. ' `( S6 |% C$ E
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    ! d! w. Y5 B" b* a2 }5 g1 |
  31.     while($row = mysqli_fetch_assoc($retval))2 V) ]1 l0 \, U6 {7 v9 P
  32.     {
    1 t3 B3 \% S' f( B0 o$ i# s! a  h
  33.         $id =  $row['id'];" |- J& S5 [9 ~9 V. t/ }1 X9 |" M
  34.     }
    # p' j% g8 M. W# g. p* k
  35.    
    5 c! V  |7 H1 Z" \# i/ U. n
  36.     if($id > 0)
    , U! P+ i2 c  M, B2 R2 ]+ v
  37.     { ) n: Q5 X% ?. f' v- I
  38.         --$id;
    , R  f6 J6 }; W. t# a
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 4 w$ N( f1 Z( O' _* d9 G
  40.     }
    ; c. I, j4 n0 L# i. U3 [
  41.     # php的文件锁,释放锁 8 B4 \% c2 i; ]% [
  42.     flock($fp, LOCK_UN);
    4 P* l5 X' B+ d
  43.     fclose($fp);& E5 t4 y# m: E- ?: f1 G
  44. ' I. I8 {/ p/ i/ D
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    3 t. p/ Q) F' i, O# N7 V8 @
  46.     // while($row = mysqli_fetch_assoc($res))5 y* v8 Y' q" `7 b% E! f" d  Y7 B
  47.     // {1 d  w7 F, \( C* Q
  48.     //     $id = $row['id'];
    2 |' I9 {; a2 f
  49.     // }, e9 I. E( H5 O% Y: n& V
  50.     // echo $id;
复制代码

" x& N* V& P& b/ C- Y
% P* F* m6 ?9 o2 N! z" k+ C/ A
抢券活动实例:
  1. public function envelopeSnatching(){
    1 a# S( N  g7 G- u
  2.         $lingqu = $_POST['type'];
    , d/ j7 c& v  r
  3.         $uid=session('u_id');//用户id: `+ s# {+ p6 u
  4.         if(!$uid){
    * C, @" A7 r$ x+ e# h/ @" i
  5.             $data['msg']='您没登录,请先登录!';
    4 }& D" l* T# C  w, K
  6.         }else if(date('Y-m-d') != '2017-12-12'){3 j7 s% h! n$ [
  7.             $data['msg']='不在活动时间内!';  j9 A- D! S* C) y2 p: p( P+ A' \5 g4 \; V
  8.         }else{
    - ^* k( e6 ?' l: x9 h/ r
  9.             $hours=date('H');//当前小时数
    , v/ F% r$ C' h& l4 Z
  10.             if($hours > '09' || $hours > '17'){
    + |- j3 L: F& @' j2 N7 P& i$ I

  11. , u2 F: X; M5 g8 g0 d9 b: n8 u- V% q
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的0 m- b: B# D' P, ]  G
  13.                     if($lingqu == 1){. N: Y) G# q' I" J. t& Y; F
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    6 o2 R3 f: m0 ?: X6 q: H& ]
  15.                         if($hours > '09'){+ U, F% `2 S4 H# t* V9 u1 `
  16.                             $num=mt_rand(25,28);//优惠券金额+ ?" Y, l  r- w+ ]0 X# T7 B/ }8 w
  17.                             $id=1;
    ) ^7 B3 z% c7 I5 ]1 [" x
  18.                         }
    " J7 j2 x; A! g2 q* e9 m. b2 h
  19.                     }else if($lingqu == 2){
    ! J( n/ ]! k* ^5 U0 r) M
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();1 j0 J! k" L' h, a) J
  21.                         if($hours > '17'){2 E; C  F: K( _0 s/ W+ }
  22.                             $num=mt_rand(50,55);//优惠券金额
      Q4 _! n+ F7 j  l# l" E
  23.                             $id=2;+ Y' Z. J# T  ?. H) }; x! Y
  24.                         }
    4 ^; P7 z3 `( Q" l8 L& v8 q) G5 a
  25.                     }4 g2 [; D) q. E  [! u5 g; r
  26.                     if(!$id){
    8 J  U+ i. y1 K3 g0 t3 ]$ J
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    . w4 W1 H; s- S2 @  Z
  28.                     }else{
    ) {5 L5 e1 P8 C2 r& ]
  29.                         if($is_lingqu){
    4 Q2 w, o( @; c5 U5 Q  x
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    : L+ I  o( V6 Y; l9 b4 z+ j' O5 o
  31.                         }else{2 N' i. Z+ @, i
  32.                             //锁表
    - T6 b$ C5 g9 M+ q% Q: R2 |) v
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');8 `# z- K- r7 m% x& ?) u) T' C
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    0 T! \% G4 M' T, |
  35.                             if($active > 0){
    ! f" j% I' I5 [
  36.                                 //开启事务
    6 h1 N2 Z& i7 Y9 T4 ]* E- \
  37.                                 M()->execute('start transaction');6 Y1 E/ e3 ~) Q5 a" E7 z
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
      c. D2 W; b) O! L! J2 n
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    , v: Q' C* j1 ]
  40.                                 $members_preferential    =    M('members_preferential');
    : q7 M8 B0 |# I4 x: ~, s
  41.                                 //对应投资金额,3 R' h  S/ ]$ j% i
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ; O& N1 h# h( [# ]
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');2 k/ v2 w6 s$ h: U6 Y" I: x/ \" \
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    * `; z3 v5 ?& I/ _' V
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    3 ?. c7 k' V# u3 n
  46.                                 if($save && $add && $add2){
    1 E8 }6 A# s' M8 h
  47.                                     //事务提交
    6 r6 R9 w% @; R, R$ A: p! o, o8 {
  48.                                     M()->execute('commit');  H0 X6 E* S, J! V! O* x
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    0 {* ^% i, p% u4 K
  50.                                 }else{; ^2 [6 g+ r# S* ^) H* u
  51.                                     //回滚
    9 ~2 o$ G# i1 e, P% @
  52.                                     M()->execute('rollback');
    % p0 W+ o' d6 t! z% i$ y
  53.                                     $data['msg']='未知错误!';) O* ~1 ^9 U) r4 T" f. r4 g3 L
  54.                                 }8 d( w: ]1 `0 g; ~1 y! j4 ~
  55.                             }else{7 o1 [7 ]( V# d3 n! B
  56.                                 $data['msg']='红包已领完,你来晚了!';
    6 B7 ~* W4 A6 Z2 b0 n% b. [" T) {0 ^* K
  57.                             }% u$ d! P+ I. ]" a4 ^( Q' ^
  58.                             M()->execute('UNLOCK TABLES');
    3 V. V, q3 ?& c5 M
  59.                         }
    3 \$ k) ?5 j$ t% f; Y
  60.                     }" F+ Q) u! b1 u
  61.                 }else{
    + I& ?; e1 n# P7 C) B+ \7 E$ A. j
  62.                     $data['msg']='非法操作!';
    * X% a1 @$ ^: Z  I8 H& V. d! v: _5 v; `
  63.                 }0 e2 ?0 h( e( s1 S$ s5 d
  64.             }else{
    3 ~( i& Z9 E0 K
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';; H; S* m2 {2 C& k3 z7 c" |
  66.             }
    ) R. p) [1 l, G6 ]
  67.         }
    2 M0 Q' Q+ l& t% h
  68.         exit(json_encode($data));
    3 B( W9 J& s( |" {
  69.     }
复制代码
6 L' [: |5 u/ G. ?! P! x  m

* r) a5 {5 v2 w6 x; |, ]
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 16:18 , Processed in 0.119081 second(s), 20 queries .

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