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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

9 `% V9 o8 m% M2 o5 F2 T8 j  U
Mysql中的锁语法:
4 ?4 W) _. N5 J, r; }LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
/ ]0 |% V) c' Y2 I/ rUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
6 ~$ k" R$ N8 q, eWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
2 F6 G/ |& q2 ?% e注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :) f, `; o: u: N
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。. t: k* A, X+ W5 P/ l% P, u
测试时,有个文件就行,叫什么名无所谓
总结:
3 i+ ~  X3 h  g; e- D项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:7 j* [% m+ I% O9 N, m" u2 k/ f7 g
1. 高并发下单时,减库存量时要加锁
$ m2 [% G- R$ g- C2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*' M, L& n; p' b- q" D2 X6 o& h. b/ w
  2.     模拟秒杀活动-- 商品100件
    9 D  E/ f' ?( O
  3.     CREATE TABLE ta  S- c: Z5 C+ J4 R% b" T" v4 G3 _
  4.     (
    # B( w% {4 c+ W5 s
  5.         id int comment '模拟100件活动商品的数量'
    $ ^  l, ]  D! A3 y. l
  6.     );' l: S! o8 h; U5 V. u7 k- b
  7.     INSERT INTO ta VALUES(100);
    0 e1 _! e! b% W: o6 o! p
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    & d3 H3 h* [: T; l* N3 `5 y
  9.      */ 1 J+ U8 e' f5 s  ]/ }+ @5 j
  10.     0 |. q: v4 ?( N
  11.     // 关闭错误报告  @0 g2 n2 c8 z' @
  12.      error_reporting(0);
    # m1 C, v; l, O5 M
  13. + L' ?! G# P5 h9 t
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址' L, o( W0 e: \
  15.     $dbuser = 'root';            // mysql用户名
    3 A; f; q; Y4 U5 I1 u+ b2 q2 N' l
  16.     $dbpass = 'root';          // mysql用户名密码
    , d% p3 ]. ~9 p/ u7 A3 H& x) |
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);* D" M* b+ b2 l
  18.     if(! $conn )
    % U1 {$ ?; w- x+ E* L4 `9 L
  19.     {# [# Z* e" l: {2 J7 D6 o9 V
  20.         die('连接失败: ' . mysqli_error($conn));
    9 p* k! F, e* j. Z8 K& Q2 G
  21.     }
    4 a" q+ _  g& p. [9 [2 f
  22.     // 设置编码,防止中文乱码! q+ n3 k2 a) A3 D5 S0 q1 d( ]
  23.     mysqli_query($conn , "set names utf8");. f' J1 `$ D5 F+ G$ T+ P
  24.     mysqli_select_db( $conn, 'temp' );
    3 \: @- [8 R- L- \- o1 ~  {
  25. " u3 H  R1 Y4 k4 q7 Q
  26.     # mysql 锁 $ F* s3 `4 Y) f/ h  B
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    6 F0 A$ p; s3 Q8 y7 @/ U  y: E
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 7 N' b* m6 L7 X6 g3 b
  29.     $id = mysqli_result($rs, 0, 0);
    0 Q" K0 D( f" D
  30.     if($id > 0)
    - P* b. u/ a& z4 [
  31.     {
    2 d& a: ^7 j+ v* u
  32.         --$id; & A- D4 p7 ?3 b& a8 S; _- q
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    $ c2 Z' j( e8 L, ~5 p
  34.     }
    + w0 s* a$ F. _+ H- `* U/ |
  35. 5 Z8 I8 b- p& r2 |/ c, c: c1 V
  36.     # mysql 解锁
    # ^6 W2 h1 K+ F
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ' h5 D- }/ B# w- O8 O. f: y
  38.     //查询解锁后的id值8 t% M. B; t4 K: T' u
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');9 I% b! K5 G" \' e  H
  40.     // while($row = mysqli_fetch_assoc($res))
    ) U8 k6 [0 [% e. [* y2 L; r
  41.     // {+ u9 D, K* n* [4 ~9 a" U/ d
  42.     //     $id = $row['id'];
    5 b) u8 }5 r$ M2 w2 j
  43.     // }
    - x0 P" K/ c0 I" M0 x+ x; B) f
  44.     // echo $id;
复制代码
9 Y9 q" R& k; h0 q
9 r0 n% n  Q2 j$ k
1 n% |5 n, H8 g# b
PHP文件锁示例:
  1. /*
    ' z: L. p) t0 X: c1 b8 U
  2.     模拟秒杀活动-- 商品100件, M' r) H) ^) ]
  3.     CREATE TABLE ta+ t8 l5 j* d) O& r: j$ ^; U# t
  4.     (, A# X( U( C# o
  5.         id int comment '模拟100件活动商品的数量'
    ; n7 w( {! W9 J9 _: f" S
  6.     );) X# t0 I, G( ^- J" @. ]* G) ?
  7.     INSERT INTO ta VALUES(100);) x' f5 m6 O, i  D" i$ u2 G
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    9 o) T; Y; Y/ u% w; ~$ B
  9.      */
    5 x1 g4 X( Z9 y& w5 e, K
  10.    
    * s; [- k9 c7 Y; {5 Z0 b
  11.     // 关闭错误报告
    9 C! V4 k) D* M2 }* w" P: U7 \) V
  12.      error_reporting(0);
    % _6 l( Q& F2 _! a+ M) r
  13. * ]/ J1 ~  t% R9 ]
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    $ V& \$ T5 [1 _( D3 c; \5 D
  15.     $dbuser = 'root';            // mysql用户名
    , r% b1 B, r0 w9 r
  16.     $dbpass = 'root';          // mysql用户名密码6 ^1 [& Y5 p. W6 i( D
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);$ n" s: l6 W5 }0 k, Z% f# O: x
  18.     if(! $conn )
    % F; w3 e' ^$ q7 _( i; s7 A! ^- ]( o
  19.     {
    ; X7 {3 D5 o: W4 V5 G$ T6 E
  20.         die('连接失败: ' . mysqli_error($conn));7 k' m& _: `* _! r
  21.     }
    ) y, ~9 e- b0 R7 i1 f, }
  22.     // 设置编码,防止中文乱码
    * z2 N0 T! Q/ P9 t# `
  23.     mysqli_query($conn , "set names utf8");" [- x& q6 S! ?% W6 `+ Q
  24.     mysqli_select_db( $conn, 'temp' );
    * \, R) ?( X0 J2 c% p( o
  25. * C& p0 G. @5 H; n! S+ A
  26.     # php中的文件锁
    3 `- a. H# H) _
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    2 O+ v* e/ z; W& Y
  28.     flock($fp, LOCK_EX);// 排他锁 ( K/ J2 m/ t9 b# ]9 h* ?6 l/ X( \

  29. / n  |2 q* ]; E" r; _& Z: E+ c
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    3 k# A: U( c5 y
  31.     while($row = mysqli_fetch_assoc($retval))! n3 n' \3 z  E4 o" T5 ^( O
  32.     {3 h2 h& A; `1 e. t
  33.         $id =  $row['id'];# V4 _$ }8 z( U; n& Y$ Q
  34.     }
    $ e/ F5 ^. L$ t1 I
  35.     5 k$ m6 L6 E! |: \" m3 K1 @
  36.     if($id > 0)
    . I2 Y0 M/ k2 @4 v
  37.     { ( ]2 }! Y& c0 Q% b8 n
  38.         --$id;
    & Q! P& U  I- S$ E' C  {
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); . l' e' h, T- ?6 T
  40.     } ; O9 L) n, k  k& a: t' d
  41.     # php的文件锁,释放锁 5 r0 g/ P7 f! d
  42.     flock($fp, LOCK_UN); 0 k+ e1 t( P9 ^5 @6 j. F8 v
  43.     fclose($fp);
    : J' e+ v5 c8 }$ P6 x/ _) e4 s0 F
  44. " O0 y5 H! ?2 i( N( l3 j" d
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');$ b" Q0 h7 f% Y. W  n  B
  46.     // while($row = mysqli_fetch_assoc($res))
    6 ~* l- w2 O  ?2 n$ a3 q
  47.     // {
    3 f6 ~3 Z. R$ E
  48.     //     $id = $row['id'];
    ; g( F" F- u- F2 g3 _
  49.     // }# N. g' R/ ^( \( ]9 N. G  j
  50.     // echo $id;
复制代码
  o* x5 [8 q) K& R8 _" E! M
' L0 o2 Q) a; E9 m8 y% c$ W& R
抢券活动实例:
  1. public function envelopeSnatching(){) u% e, s$ M6 F5 Q% c* D6 b
  2.         $lingqu = $_POST['type'];8 ^+ q  F$ P- F; S; X7 ]8 G& l
  3.         $uid=session('u_id');//用户id
    & Z& @& [7 Y: H: D2 A! g( r- w
  4.         if(!$uid){
    : d/ d' V8 v# v2 g# N0 ~) L& d  L
  5.             $data['msg']='您没登录,请先登录!';! m% \( d. h' G2 ?3 G
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    $ w# Y2 Q- \( u* Y! N0 I: v
  7.             $data['msg']='不在活动时间内!';
    $ D3 ^- X0 ]" J, }  B" N
  8.         }else{
    1 u0 t! B- o- H
  9.             $hours=date('H');//当前小时数, T: X+ j4 K4 G: a
  10.             if($hours > '09' || $hours > '17'){; v) p* _3 x. E' n* P! J3 ~6 Z( Y

  11. . ^. F: y. T- j# T( y
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的7 a6 E1 c; {, K5 u2 I9 Z
  13.                     if($lingqu == 1){
    ! b2 i9 I. A+ G8 `  C
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    , n5 W9 q- c" E; V, I$ W
  15.                         if($hours > '09'){$ b  I0 H* [  a3 @2 o
  16.                             $num=mt_rand(25,28);//优惠券金额# k1 U# K0 O$ s% m' [+ N
  17.                             $id=1;
    9 M* m" O# _) m! ]& x7 O
  18.                         }- Y0 n2 {' |) U# b8 W# }# P
  19.                     }else if($lingqu == 2){, Q3 \; Z8 r3 g' }# Z5 F* r* X9 e
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    ! s; ~, x8 Q4 ^( M) e
  21.                         if($hours > '17'){! J& U$ W+ R( D  j# t( C4 y
  22.                             $num=mt_rand(50,55);//优惠券金额2 u, V# i! o* t3 U; E9 i# S
  23.                             $id=2;
    - N- O: {2 }* j: P: Z
  24.                         }
    1 S5 K& @$ ~( ]5 }( n
  25.                     }
    3 w3 c4 q1 U: t7 p# o$ J
  26.                     if(!$id){
    * \6 L( D# z$ Z! x
  27.                         $data['msg']='时间还没到,晚点再来吧。';( e0 {. M$ H  r4 U  L
  28.                     }else{
    1 t+ |7 |! X8 x
  29.                         if($is_lingqu){% G6 q7 R( }' U% D
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';5 f  ~0 ?: p" v/ E4 v4 s/ I8 Z  _
  31.                         }else{
    " e$ z* u( t8 K
  32.                             //锁表
    / i! @5 O) i1 @3 A  _1 G8 f
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');5 A& \- ?& i" X) V2 @! d% g
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    ) d. S* B* Y( V: k7 S% ?" {8 F
  35.                             if($active > 0){
    9 Z& j6 I, j, a  T  Y' w+ e" w! {/ v
  36.                                 //开启事务
    # a: W& ^  w, `
  37.                                 M()->execute('start transaction');
    8 a: I) v% Z6 F, f/ h* x4 U; m7 N
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    ' d- Q6 q  u/ s$ m% U. G6 W
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));5 ~9 V" i6 P- e  L& l
  40.                                 $members_preferential    =    M('members_preferential');3 d: Z# L: P3 e% Q  `
  41.                                 //对应投资金额,
    * v6 g2 l# O) J" k, x/ I  w' w
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ( @0 K7 w! B  d: I2 d# ^  C
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');; l3 G1 O8 _7 N7 B6 J# {  x2 Z$ h
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    - k( \: S: @1 ?2 ^0 x; q  H
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券- u( p1 }* y) P* i/ ]; R  d5 D4 f' G
  46.                                 if($save && $add && $add2){& H. Z! a* \# |4 s% F. n
  47.                                     //事务提交
    3 ^% w. F& j& e& J
  48.                                     M()->execute('commit');* P2 Y/ _5 K: Y7 I; r9 r9 j% Q
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';6 Y; C/ q, P. N
  50.                                 }else{
    ; g; t& W$ T8 [. N* L0 a
  51.                                     //回滚
    8 A% y5 Q) p' P& e% N# _1 p! A
  52.                                     M()->execute('rollback');
    9 q+ J% W, C; e5 J- g  e( G
  53.                                     $data['msg']='未知错误!';
      W& G$ _- F! s$ E$ W7 F
  54.                                 }0 a/ y* J" b* y1 J; L7 w
  55.                             }else{
    5 K& E4 j3 d# A) K3 L) M: @
  56.                                 $data['msg']='红包已领完,你来晚了!';0 |( S5 I$ m0 n4 k
  57.                             }: L$ o3 N7 F! }
  58.                             M()->execute('UNLOCK TABLES');: d1 Z7 Y- a; q
  59.                         }, U- x  S" L' O- v- w* X* O
  60.                     }
    5 }9 l( F9 A3 g& Y
  61.                 }else{
    " {' c9 j) s% p9 s
  62.                     $data['msg']='非法操作!';
    1 m3 @. X; O0 D
  63.                 }
    4 p: s& J1 o. `9 h3 A4 X& ~
  64.             }else{; G' l: x' }/ W  x
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';9 G- N+ A  V$ d% H0 k0 s  ~
  66.             }
    3 E; A% l% p% c' \; I0 y' |
  67.         }; a, f2 g/ o5 \9 I) c8 h! x
  68.         exit(json_encode($data));! Q4 `5 J( F" K. j4 n
  69.     }
复制代码

$ a# E  m3 h- E6 h9 R8 X
/ ~1 o7 u( _! m7 i3 o( M/ n
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 21:24 , Processed in 0.052717 second(s), 19 queries .

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