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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

7 [% R3 S" y) x! S
Mysql中的锁语法:/ Y6 e* v7 j4 ]& s* Q
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】. k2 O& ~" B- W) c6 F0 k% T6 F1 c
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
2 x" O% C: P: e9 pWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
8 M! f3 M  k: g5 c$ i9 K  r注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
) ]" V& q# J& r2 u) g文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。. M$ R6 J! j/ y
测试时,有个文件就行,叫什么名无所谓
总结:
: @. T" |: J, r9 z项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
$ g  w0 O" ~- P* N+ C1. 高并发下单时,减库存量时要加锁9 l+ C3 q9 I8 h& n
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    8 k. D# C) v# q
  2.     模拟秒杀活动-- 商品100件
    2 c1 I  x6 C* T2 Y8 O& D
  3.     CREATE TABLE ta/ g" @7 U3 c2 u0 s* q9 E5 g! d" F
  4.     (
    ; G6 W) X' P# |. z# Z
  5.         id int comment '模拟100件活动商品的数量'
    # D( R( g$ Y2 p: X5 c; v. r
  6.     );$ j# I0 @2 G1 H" e
  7.     INSERT INTO ta VALUES(100);3 P' m7 R8 h7 M% i7 K8 M% J
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    5 I. o8 a( ]+ l2 u
  9.      */
    ) [; P- x. m3 X( S3 Y7 H
  10.     5 Y4 A+ h8 a, e+ o$ s
  11.     // 关闭错误报告
    $ Y8 H& M' K4 B) R
  12.      error_reporting(0); 2 ~/ w8 E" a# l3 i( B! R( P4 K
  13. ( n  w, ]3 `, |7 P4 g
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址% D; [! U' j7 H7 ~- Q
  15.     $dbuser = 'root';            // mysql用户名9 ^: L, c5 S- j8 h  ^* J9 V5 C7 M
  16.     $dbpass = 'root';          // mysql用户名密码" r  D! [8 v* d3 A
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);0 m  \" l% f8 O! K2 I, V
  18.     if(! $conn )
    2 g- F$ O1 {- w; b! l
  19.     {% b, {+ b' d+ U; O: ]; @
  20.         die('连接失败: ' . mysqli_error($conn));. b" l0 O1 i$ V
  21.     }& ^: [! Q# g8 V2 H
  22.     // 设置编码,防止中文乱码
    9 D# _; V1 ^2 ]: K
  23.     mysqli_query($conn , "set names utf8");. I/ X$ l/ I* r* w6 K# }
  24.     mysqli_select_db( $conn, 'temp' );
    . H8 q3 u- _/ O& j3 J" V2 p

  25. * [# P( h4 J* Q' F' j* K5 i
  26.     # mysql 锁
    / A4 T, E- {& `& V5 Y3 X' G
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 7 \) n- w8 p$ i- K) ^
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); - d) L+ o% [5 u  _1 X! D! ~: h
  29.     $id = mysqli_result($rs, 0, 0);
    ; q, ?% j  q! n+ U6 y. b% P
  30.     if($id > 0)
    ' S/ ?( ?- v2 E" J% ~% N1 b
  31.     { 0 C) _+ L6 `2 I% h4 h
  32.         --$id;
    + k+ B* Q" T" i
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);   z3 q3 |& n* Z% X& `
  34.     }
    ; a/ U1 x$ A6 G3 S' [
  35. . f! y& u) J/ u" s4 G
  36.     # mysql 解锁 5 r2 L" F7 D- P4 d1 d
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    + n# s0 r) ]: D2 \' a9 y1 Y( Q2 g
  38.     //查询解锁后的id值4 {: y9 k7 B2 {  x
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    , x, [. Z# D* v% g& z* y: T) l! w) l
  40.     // while($row = mysqli_fetch_assoc($res)), B* j. `; Z. E+ i, ]* V, a
  41.     // {
    5 h  K$ s" b( z3 z& e" t1 F- R1 S
  42.     //     $id = $row['id'];: F) ]8 P# y( N8 ]7 Z) S* v- F3 e- Z
  43.     // }
    2 d9 u, v; g6 Y' _
  44.     // echo $id;
复制代码

5 e4 u7 Y% A  @( ?+ @& Z+ g/ d7 }% u/ Y& E3 p9 u
, u& ^$ s3 [% `
PHP文件锁示例:
  1. /*
    % ^  Z9 R4 W0 D/ M3 }
  2.     模拟秒杀活动-- 商品100件
    + Z2 M4 q3 y9 r# t! W7 W* k
  3.     CREATE TABLE ta
    ; _  _& f) T  q5 Y4 P; Y# O6 B
  4.     (9 T8 D: n2 ]1 e
  5.         id int comment '模拟100件活动商品的数量'
    $ E/ `: z& {. H
  6.     );/ M. L( k! q. T  |, m; f5 O
  7.     INSERT INTO ta VALUES(100);
    6 y. I2 U8 t8 ~/ z& u% Z5 U
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    - e3 ^- x5 o5 }6 a
  9.      */
    % `, D0 b- H; Z. Y3 @9 @0 h+ N) Q
  10.     ' A3 y0 S, Q3 `
  11.     // 关闭错误报告
    & l% a: J+ ^) l& E' v3 b
  12.      error_reporting(0);
    0 h: K) Q6 U1 V# F" e: c- I

  13.   T; R9 o+ J1 u5 ]5 a2 {3 d9 T
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( e( ?5 n7 c$ J' M9 ?( `! h5 V4 n
  15.     $dbuser = 'root';            // mysql用户名! p& d1 f( D& a" @2 \3 z2 a
  16.     $dbpass = 'root';          // mysql用户名密码3 V. s( W" T) M  T5 ]
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    8 z7 S- ]0 @6 z' K0 d6 C
  18.     if(! $conn )
    : z6 v* i: `1 m' Q
  19.     {- m" E# r9 u9 n, I4 f1 O+ |
  20.         die('连接失败: ' . mysqli_error($conn));" S  O  c: w% w4 A
  21.     }
    4 o) [% k: E- P' d$ N9 A8 B
  22.     // 设置编码,防止中文乱码
    ' x. e4 z4 m% B2 @2 w
  23.     mysqli_query($conn , "set names utf8");+ J1 D8 ~$ t: A4 S$ J3 p
  24.     mysqli_select_db( $conn, 'temp' );
    * Y. `( ~9 m+ w6 b: @9 y5 ^

  25. . T0 j& i7 i: Q( v4 t8 Z
  26.     # php中的文件锁
    / h+ B% n8 F4 W/ m+ ^7 i% \
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 , j$ X( W3 J9 A
  28.     flock($fp, LOCK_EX);// 排他锁 5 S7 U0 S( ~5 f. G  Y. o3 S2 b

  29. 8 `; t  m; c; B7 N% v0 Q
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    0 P/ h, U6 ~6 k- {. l
  31.     while($row = mysqli_fetch_assoc($retval))) ~$ `; B- W9 A# r( P& v/ Y5 n" Q$ U
  32.     {: R1 {, L* S: ^' e; f+ K/ [
  33.         $id =  $row['id'];# g; Q: Y4 v- d5 L9 S
  34.     }5 \# z$ V/ ]% ?6 a/ N" O
  35.     + c  S  C3 }/ R. c! f( X
  36.     if($id > 0)
      V: }- b8 w; l9 x( I& W
  37.     {
      K$ u2 x% G. m( {
  38.         --$id;
    $ U# p' {- T& l9 k1 a
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); ' b" P5 ~( a* i, c' D# K$ z
  40.     } - B4 G! ^; T0 q$ m2 J9 w' n
  41.     # php的文件锁,释放锁 ' S7 ^7 S6 E. k; E6 P6 S0 m
  42.     flock($fp, LOCK_UN); & Z/ G- R8 v. A! |) b; t
  43.     fclose($fp);
    ( s6 J* n# a# @5 A, K' m* x) s

  44. & I* @% b$ G' c/ {2 R  X5 {
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');# a* N% [' V! i7 g; M
  46.     // while($row = mysqli_fetch_assoc($res))5 o1 K7 s2 o( h2 o% N
  47.     // {
    6 Z' r. S/ m1 z- o; v; w* q% Q
  48.     //     $id = $row['id'];0 B$ _1 ]3 Y/ C
  49.     // }( ~  V; S) M4 D1 D) p
  50.     // echo $id;
复制代码
3 d, J3 u3 ^% D

, X0 S# l" u4 o5 n" _- n* J# k' Y
抢券活动实例:
  1. public function envelopeSnatching(){
      s' i# ]; @  V
  2.         $lingqu = $_POST['type'];0 p4 `. e! y* r' t% S$ v
  3.         $uid=session('u_id');//用户id
    & c8 {$ q; x4 G8 n% _% t
  4.         if(!$uid){7 g! ?1 R% Z* ^( v8 a
  5.             $data['msg']='您没登录,请先登录!';
    ) [$ ?7 v" E. {( A) A
  6.         }else if(date('Y-m-d') != '2017-12-12'){( w  J: W) N" |$ h/ ?5 v
  7.             $data['msg']='不在活动时间内!';
    0 S, `% y4 f! P; y6 o& o
  8.         }else{
    $ h/ a9 \3 R3 W( ]) b  z3 M) h
  9.             $hours=date('H');//当前小时数1 k3 E% G0 L4 {" F: m: Z3 V
  10.             if($hours > '09' || $hours > '17'){
    + D+ j- y& W$ h5 c* |. {

  11. 7 g; D+ @2 W5 o4 J& ]
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    0 ~- H' o. U& ~  K# T. b
  13.                     if($lingqu == 1){  ]# y0 h: V# [) |' L1 J# `3 d3 ~0 M
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过& E8 [( M; i. U# }) `
  15.                         if($hours > '09'){6 E. r, }9 i( ?
  16.                             $num=mt_rand(25,28);//优惠券金额- F0 c. Q" _+ C/ j8 h5 N
  17.                             $id=1;! `' |. _& e+ c
  18.                         }
    0 E. Q0 K5 n) d, s2 t
  19.                     }else if($lingqu == 2){
    : S- @5 W% U% d4 q! j
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();; C( z: j- ^# l1 V/ o
  21.                         if($hours > '17'){
      y, ^* u4 A# s
  22.                             $num=mt_rand(50,55);//优惠券金额0 d0 F$ T3 f8 g" x/ \  U: K
  23.                             $id=2;% C5 `% P3 M" a* ?, u. r
  24.                         }% F1 }2 d0 d) c$ M7 ?7 s' m
  25.                     }
    ) F4 q8 h+ ^. ?: ~2 O
  26.                     if(!$id){$ S2 W5 {( k  \' a
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    ; }0 {+ _6 k$ z2 E4 T. ^2 f* y2 r
  28.                     }else{
    * t; Y) n, O9 Q$ _9 y  q* \/ s3 W
  29.                         if($is_lingqu){
    , p/ ?! l" W; f( Z4 q2 X" i' }, u
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';3 V4 p5 |( R: t. s
  31.                         }else{
    3 [' w9 G3 B8 K4 h& T+ ]7 n* v) p
  32.                             //锁表
    7 R' w1 w# A, D$ X0 i2 b& J
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');3 o9 ?' T$ u3 j7 u' f
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();4 e1 s( J3 M9 ^4 ^8 M9 j- @
  35.                             if($active > 0){) n, o) u7 y3 @% ]7 V: u
  36.                                 //开启事务
    5 A0 S+ @6 I2 d- q3 g3 O3 `9 G
  37.                                 M()->execute('start transaction');
    7 K8 E6 k9 D0 n. O" [9 `4 e
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));" Y9 n2 Z' V- i, L1 T
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));1 S6 M8 J; t5 ^! m" \8 S
  40.                                 $members_preferential    =    M('members_preferential');
    ( w# N' i4 s9 |* h  a
  41.                                 //对应投资金额,
    + P+ [+ F" E; M* Q' \
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));; e1 V: E1 B/ U1 Y8 G6 O
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
      ?. ]8 x6 b/ [7 g2 @3 J) ?
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    % H  h* @/ Y. L% K. |
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券7 s6 ?. Q6 r3 K/ x3 L
  46.                                 if($save && $add && $add2){+ a' ?6 C$ O, l4 H- o
  47.                                     //事务提交
    7 S# Q6 F; l* r4 m) d
  48.                                     M()->execute('commit');3 }4 W. O* O6 @6 K3 Q
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    3 J; X1 b+ Z9 ~! D; l# [
  50.                                 }else{" U6 o9 u9 r3 E; ^1 A
  51.                                     //回滚5 ~9 D# v; x* S8 l1 k( T
  52.                                     M()->execute('rollback');# X* ^6 p$ k* j
  53.                                     $data['msg']='未知错误!';
    7 z4 P# t1 J( l6 |
  54.                                 }7 ]: `, R2 e% D9 J* M' x; ~
  55.                             }else{
    $ v' a  }# e, u2 a- i# f6 N6 r- X
  56.                                 $data['msg']='红包已领完,你来晚了!';) `" Z8 @) b( g
  57.                             }
    0 @- f8 ?$ {+ I- n9 x! I' c# ~  g" y
  58.                             M()->execute('UNLOCK TABLES');- Z! V4 n, w3 U8 I! G" k
  59.                         }
    % w# _7 B/ p. _7 N0 L( A, {* J
  60.                     }& x7 M5 ^/ }+ j5 \# g: E+ P0 }
  61.                 }else{
    % s( Y- K& \# N; ^( J' _$ x3 e0 Q
  62.                     $data['msg']='非法操作!';
    6 X/ ^: g7 ~% ?& k. @
  63.                 }
    - u/ i0 k3 m- d. z
  64.             }else{2 \3 N* d2 e" `# w( @) j
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';7 I) F" M' B- [* Y" l: F/ F
  66.             }4 u" o0 U- V* m/ U8 T2 _
  67.         }
    & X+ w& b: J' Y, }: T9 v% d, Q  P
  68.         exit(json_encode($data));
    4 r7 a: ?$ w, v8 C/ u
  69.     }
复制代码

( {5 P* a  [. N& E
, {& h$ @+ I" M9 f3 ~. _2 e
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 00:59 , Processed in 0.120768 second(s), 22 queries .

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