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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

4 G2 y2 a" q# `
Mysql中的锁语法:( O6 `8 S' A& ?" p( J4 l( V- \
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
$ E2 S5 T8 Q" h: D. kUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
7 f7 ?; @, W4 f$ P, ?Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞* m/ `% T" |; p( {
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
" t/ _& i0 D& c3 c" t- Z文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。7 @+ x/ ^! J8 A7 r) Y6 R1 f
测试时,有个文件就行,叫什么名无所谓
总结:' a" [; J/ r3 Y+ O3 V
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:" p1 F  i1 v) M2 o; J5 M  K! ]+ w6 Y
1. 高并发下单时,减库存量时要加锁# B- S: o; |( ^
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    , K  [" b( S& F" V/ |9 J
  2.     模拟秒杀活动-- 商品100件
    / y1 }6 r- }" n$ J+ S
  3.     CREATE TABLE ta
    $ }3 {  I+ \0 D8 f+ [
  4.     (
    0 x4 [& U6 Q0 n+ u
  5.         id int comment '模拟100件活动商品的数量'
    % |: _' ?4 O2 p7 n! r8 I. t* ~
  6.     );$ s( ~" g, q0 |( s6 T8 ~
  7.     INSERT INTO ta VALUES(100);
    2 ^3 W# z# z! I, F
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    " ]. [) b" B. m+ Z- G, W
  9.      */ 1 L) d4 n. _+ m* g4 E& h
  10.    
    - W3 a/ o& z8 ]
  11.     // 关闭错误报告9 j/ `7 r8 q7 i0 x' [1 e0 j! |
  12.      error_reporting(0);   h0 {3 X7 N2 Y! C8 R% S1 n( N

  13. : Q* S1 g: a% d) ]% Y1 I* L
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址  ]3 |4 A. z3 |: u- ?
  15.     $dbuser = 'root';            // mysql用户名
    ) i. ]3 t$ x' ^6 ~
  16.     $dbpass = 'root';          // mysql用户名密码
    # {% `5 K7 A9 `: n. w* L6 T2 c
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);4 E: ~+ X1 z$ u0 \6 {& P
  18.     if(! $conn )) |1 z7 i; H/ G& S
  19.     {
    7 I, P1 `' l+ {/ V& P6 x
  20.         die('连接失败: ' . mysqli_error($conn));1 a1 s" ?- P& l
  21.     }5 g3 L& j, l/ ^& q
  22.     // 设置编码,防止中文乱码
    . y" [- }* t6 n/ s) I6 \9 G4 A' w, u
  23.     mysqli_query($conn , "set names utf8");9 e7 s4 q* a- ~- H3 ~0 \' D& q
  24.     mysqli_select_db( $conn, 'temp' );
    . k0 n8 P4 R# }( @* }% ^0 |0 q
  25. # b' G- {6 o1 S$ l- b1 a
  26.     # mysql 锁 5 r8 o5 q  Y; l( u4 w
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ! J- L+ U- d# D" c" M$ P
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 0 c/ Z& ^, N( w: t
  29.     $id = mysqli_result($rs, 0, 0);
    & m- u" b% [% y+ q( }( u6 e" O
  30.     if($id > 0) 8 _' J$ A8 b1 B/ W& M3 _
  31.     { ! y$ y# J- w/ D$ I$ J: s
  32.         --$id;
    6 N, s# Z+ X( n! i) ~/ m
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    " O& k: J& t3 \7 M' ?
  34.     } ; X8 L' p, }2 X2 _, i
  35. 7 D. ]& A4 u* ?6 v! T- R/ H$ a
  36.     # mysql 解锁 . ?2 M, L9 l5 j: \
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    " P' y' r0 s/ p" ~5 T+ ]6 t
  38.     //查询解锁后的id值
    ; E$ D) m$ a! V9 k# m/ |8 i/ G
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');3 t! J2 M! ?$ E8 |/ `
  40.     // while($row = mysqli_fetch_assoc($res))& Z: W' R& r( A  J+ i1 J( c& i
  41.     // {
    4 k7 ~5 A7 ]$ x) y  l" Y
  42.     //     $id = $row['id'];/ [& ]0 v  n5 `9 V' N, D
  43.     // }4 Q1 H5 ^* G  ]% [8 e
  44.     // echo $id;
复制代码

# j$ c, _, j% _- E/ r( ~' k6 C) T- U9 |/ b0 F$ h
# W# Q" A$ N% R: |
PHP文件锁示例:
  1. /*. O! o9 m0 b( j) S# D+ m7 H
  2.     模拟秒杀活动-- 商品100件9 q5 r9 O/ H: F6 ^8 P0 Y5 d
  3.     CREATE TABLE ta9 Y6 ~( c# k0 ]! q
  4.     (
    : U. q1 c8 b" Q: P) u+ y! t
  5.         id int comment '模拟100件活动商品的数量'6 s. O% B  L6 {+ R" ^; r
  6.     );( `& F8 K2 R( f0 ]4 d$ H$ y
  7.     INSERT INTO ta VALUES(100);1 ]+ i* I" U/ w8 l+ n
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件; {4 O# W6 u4 a* f
  9.      */ 2 z5 I& d* p5 F2 S
  10.    
    ( V+ L# G8 n$ S, ~
  11.     // 关闭错误报告6 z/ `/ d  [: h$ F8 f
  12.      error_reporting(0);
    7 c' [' {3 g/ `4 m

  13. : k" V$ j- `" W9 s
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址- n9 q8 F3 G. x, D" a
  15.     $dbuser = 'root';            // mysql用户名
    / P  m' R) O- h* s  Q
  16.     $dbpass = 'root';          // mysql用户名密码
    ! U+ K4 ]0 t* c& V
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    * U8 V: Z3 K! g& `1 a
  18.     if(! $conn )! O! A0 d# h& p* b- [" z: I& ?
  19.     {
    $ w9 e- A2 O' G( v/ o3 v: j
  20.         die('连接失败: ' . mysqli_error($conn));0 g7 y/ H, }+ r+ B' {. C8 b. y" T
  21.     }* x$ x1 S8 X2 z& s; Y2 b- n
  22.     // 设置编码,防止中文乱码3 v8 k3 L# C) X! \& t" I& u: S6 H
  23.     mysqli_query($conn , "set names utf8");
    . a# O% g) t/ z: q4 G+ @
  24.     mysqli_select_db( $conn, 'temp' );
    9 i6 K: D& O- w

  25. ' b' N( s* ^) U# v) f
  26.     # php中的文件锁 # h, D  ?  {8 J4 H+ [
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 3 O9 f8 ~% }& T$ S$ Y+ ?. ~3 a5 j
  28.     flock($fp, LOCK_EX);// 排他锁
    " B0 _; T6 f9 m- X6 e

  29. & t3 V! X4 y4 l' h1 M0 Q
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ; R1 R) I5 h2 p$ y" ~7 C/ U
  31.     while($row = mysqli_fetch_assoc($retval))
    5 {6 f" O' B- x- V9 y) X9 R* ?2 N
  32.     {! U0 L7 x4 {/ [5 ~: G7 K
  33.         $id =  $row['id'];: r. m; a7 I) s9 p2 N
  34.     }& N3 V& ]' U5 H+ t
  35.     ) C* P) h2 T* F7 v% c" B( [3 q4 S
  36.     if($id > 0)
    ! i, P- Q3 A. |" K5 W8 Q
  37.     {
    * R9 B- @7 s5 R$ v1 l' U" a
  38.         --$id;
    + x, G% I6 s8 G( [2 O4 U& l
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    . c) \9 P( w6 ~# u9 n
  40.     } ; }1 o" d$ j# D2 g8 ]8 T" C5 m
  41.     # php的文件锁,释放锁 0 m( B  k0 x3 h) P
  42.     flock($fp, LOCK_UN);
    ! W+ s1 u% a" E3 u9 s
  43.     fclose($fp);
    , w4 G. z  @4 {( M
  44. + ]# B! }/ e# o. d; Y6 ?
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');, G0 Z) P$ m& }# C: R. u
  46.     // while($row = mysqli_fetch_assoc($res))
    - P$ k2 H1 s( z
  47.     // {
    " M2 I" t( q, m8 u% H4 a' j5 C
  48.     //     $id = $row['id'];
    & B- @/ _" K* x. h4 N  h3 `- l
  49.     // }
    / D' k! R  h/ {$ x) ]' [9 m7 k
  50.     // echo $id;
复制代码

3 A9 q+ b" m5 i- o( a4 A4 x: b! n% K. E' @; j  u4 l' F
抢券活动实例:
  1. public function envelopeSnatching(){
    : q, `# g; _. V) {- c! Z
  2.         $lingqu = $_POST['type'];
    : q" i# q. t8 k7 y0 }
  3.         $uid=session('u_id');//用户id& p5 ~$ {/ o: F' M* U) X
  4.         if(!$uid){2 Q4 g# O0 U& u/ Q
  5.             $data['msg']='您没登录,请先登录!';' O! ~! O* O5 h0 t7 u! {" E! \3 N0 B
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    , M% V" }! C7 e
  7.             $data['msg']='不在活动时间内!';
    * u3 c' o$ E) N- H8 R" Q
  8.         }else{
    & w, ~7 e$ Y: a9 P/ H
  9.             $hours=date('H');//当前小时数" e4 c3 w1 W8 [7 G: H
  10.             if($hours > '09' || $hours > '17'){
    5 v0 u5 h( \- \  O7 T# C
  11. 0 D. m  s# w3 }* P# i
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    * W% \/ c2 x! ?5 `1 q
  13.                     if($lingqu == 1){
    - z4 e4 A) Q0 h( W$ s, D( [
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过8 k2 o$ P1 F0 T% w7 h" R6 ^
  15.                         if($hours > '09'){
    ; L7 j9 L; w$ m9 u& b
  16.                             $num=mt_rand(25,28);//优惠券金额
    $ J* N3 {. R$ _* t! A# Z& v
  17.                             $id=1;' G: Q8 v/ t* k8 L7 {# n
  18.                         }+ J1 _' I4 C* v) L, f- ]
  19.                     }else if($lingqu == 2){) W7 ?* ^' _7 L" c' H1 _
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();- r6 I, T& X3 K0 c! _( Y' \
  21.                         if($hours > '17'){
    * G& l5 D& @+ C  Z. O: `6 Z$ |
  22.                             $num=mt_rand(50,55);//优惠券金额4 r. \; |4 P! c
  23.                             $id=2;$ y# c$ b7 a: h$ O0 ?
  24.                         }. W( ^/ |' w5 y
  25.                     }: @  |5 g- r8 ]+ R* z) i
  26.                     if(!$id){
    0 A' t2 b$ z5 x1 P3 i9 M" b
  27.                         $data['msg']='时间还没到,晚点再来吧。';" S/ ]/ [- h. [& W
  28.                     }else{
    3 r0 t( Y+ Z0 [. i* [+ }
  29.                         if($is_lingqu){
      ^5 K( x3 C/ b" h7 t
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    0 `8 K$ |- U/ q  k  O! ~1 v
  31.                         }else{
    $ x5 M" L; p( m2 q) F2 Y
  32.                             //锁表
    % ?9 W3 v7 i4 ^- r+ N
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');1 E! L* ~& Y: S. h# k! h5 i
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    % j5 e9 l- G/ h) Y# t% \
  35.                             if($active > 0){
    1 P, E5 [) D1 h5 e
  36.                                 //开启事务  H8 F8 ~4 E6 l+ {
  37.                                 M()->execute('start transaction');
    7 x; e; G/ u8 I3 A7 A1 q7 j* j
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));; E& Y. n* m" L. a! o. |4 e1 F
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));& G5 A. `' v. T4 _( |
  40.                                 $members_preferential    =    M('members_preferential');  J& p/ p  G8 o) H0 m
  41.                                 //对应投资金额,8 Y! l7 W2 `* ^% ]: `1 e" k
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    . k; c; U+ V( v, _
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    , L$ J  L* {% F. [/ {+ P" A7 E
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    ) h; u( d  I6 d/ X
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券; S( k; Y. {* [4 s: [
  46.                                 if($save && $add && $add2){$ ~; _9 r& X. T) q5 c2 o4 Y& x( H
  47.                                     //事务提交, P+ ~2 w4 P* h* X* h1 @
  48.                                     M()->execute('commit');! a* g/ q4 J  {. E( r4 U( p
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';% P* u1 e$ {, O' Z; d8 ]
  50.                                 }else{
    * u" N0 p7 X0 B0 w% h+ C/ H
  51.                                     //回滚
    + |  z8 X$ R5 F& n
  52.                                     M()->execute('rollback');  m9 m$ I( {; J% d6 W
  53.                                     $data['msg']='未知错误!';
    : F2 y7 x+ `  ~. S7 b
  54.                                 }
    5 B# X4 B' v( w% H" a' C
  55.                             }else{* ], g! k% f+ d
  56.                                 $data['msg']='红包已领完,你来晚了!';* O$ y. n9 e! x0 A( z( e3 S, ]! W
  57.                             }
    * {+ k# r. |4 d
  58.                             M()->execute('UNLOCK TABLES');
    + z2 I% E( D0 m8 \4 [
  59.                         }; t- j% n, x  U% E  @* ]9 e
  60.                     }8 n2 l% Q2 V3 j0 N
  61.                 }else{/ O5 D2 m' u4 v- f
  62.                     $data['msg']='非法操作!';+ N# \' P) z$ e
  63.                 }
    , w9 A- Z2 ^7 Z4 k* `  W8 u
  64.             }else{
    0 r! E+ I7 V# R0 m9 I/ q" y$ ^
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    - b2 v4 f0 Z* s1 p8 f! G1 d
  66.             }
    4 t/ }3 J; t% C6 }; }4 x- J
  67.         }( l/ J. T7 p2 F2 y  e9 Q
  68.         exit(json_encode($data));5 l7 \( X6 K" \1 \$ x9 ]" l
  69.     }
复制代码
+ ?. f3 f( j% k8 O3 W0 o1 \3 f4 F" g# p

3 w, e4 f3 W+ n4 ^  c: v5 B
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 17:02 , Processed in 0.116713 second(s), 19 queries .

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