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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

" P# N8 M' K9 s4 }  l" K
Mysql中的锁语法:
- G7 X& u8 t; u# S$ Y3 I5 ZLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
6 ]2 d% W7 Z1 ^- a6 LUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表0 w6 z) i2 \% e* k" o. Q
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
7 u% E  J8 a9 Z7 _" L2 A6 `. a注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
0 a+ x; U$ i) S- q% A- `文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
+ J+ J& J- y8 }/ g7 p+ V测试时,有个文件就行,叫什么名无所谓
总结:) t+ ~- E0 n! t7 A2 u
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
8 H( S5 `& a. L! m8 `5 E. h2 ~1. 高并发下单时,减库存量时要加锁
2 l* y1 p5 J: y4 [+ n# L+ P/ j1 _2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*1 _' L# K: \5 ]5 T# w: R; c
  2.     模拟秒杀活动-- 商品100件
    " @& D4 Z$ Y  a* p
  3.     CREATE TABLE ta  W7 Y0 E2 A7 D; |
  4.     (
    - z6 U- ~, N  ~7 G8 D8 ]& J3 v! s
  5.         id int comment '模拟100件活动商品的数量') r1 Q2 W, e, _" {% V) x
  6.     );$ l* t3 i# T$ e- f8 j3 K
  7.     INSERT INTO ta VALUES(100);
    + a5 ~0 ^; T4 o
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    " ^: V0 k6 }/ [* S' a
  9.      */ 2 q+ s5 k1 c" a6 E. _
  10.     # M0 l0 A1 q/ A; C% a. j/ R) l9 ^
  11.     // 关闭错误报告
    * |0 f% I  \; [" d$ P
  12.      error_reporting(0);   y! o" P7 F9 |3 I/ }

  13. + V* u* b- W$ A9 F
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    . p# S- \7 D: M) r, s% _+ ?
  15.     $dbuser = 'root';            // mysql用户名
    % S: z* V- r( }3 \
  16.     $dbpass = 'root';          // mysql用户名密码
    : x& g  G" {$ [, W
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);5 L# C8 r+ K4 _$ w
  18.     if(! $conn )6 g4 o1 v6 F1 D% {* P+ f3 f
  19.     {/ h: |& V0 y' B
  20.         die('连接失败: ' . mysqli_error($conn));  g/ `- E* ~8 o4 k4 u- a- d3 ?
  21.     }
    ( Q9 P1 z. L: }: B8 @$ I+ m- Q  `
  22.     // 设置编码,防止中文乱码& k6 N8 ~( c5 e* j8 P, @
  23.     mysqli_query($conn , "set names utf8");
    " b+ m! \- I: q9 t- k) Y
  24.     mysqli_select_db( $conn, 'temp' );
    / J# M6 i" s: n4 I2 ?9 R/ ?

  25. " i6 S7 [; r9 Y" R1 L
  26.     # mysql 锁
    9 p! [9 h0 @3 N8 _$ M
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 4 `* u& M. k) ]9 a
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 5 C, O- E0 u% H  z* @: U
  29.     $id = mysqli_result($rs, 0, 0); / g3 l4 Y" v7 W9 f7 b+ E
  30.     if($id > 0)
    0 P1 r9 l! E7 {' B" T" w
  31.     { 5 x! M8 j6 w" t4 ^+ E
  32.         --$id; , m' r- V# l$ E
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 9 _+ j. T3 V. D4 R/ [/ Z
  34.     }
    ; ~" ]. h$ t, H, Q$ e

  35.   P6 q; D% _& o2 r* h6 C! H" d  \, l
  36.     # mysql 解锁 4 V+ y- b8 H) T. H% R) ?9 m3 l8 v# n6 I) i
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ; V4 E8 _  c5 k& p
  38.     //查询解锁后的id值
    , N3 k( r9 `: M! _/ \
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    * |" q' B: d/ Q% C( s# e& \
  40.     // while($row = mysqli_fetch_assoc($res))$ B3 O4 Y" S" w$ i! f
  41.     // {+ r2 J3 S* R( S5 C# E
  42.     //     $id = $row['id'];# b/ b# u# @) \8 }0 Q* H7 C
  43.     // }
    . N( k* E  h# W/ g( D- V- e: n
  44.     // echo $id;
复制代码
) ^* t5 X# T8 \8 c- m! G; ~! L: n
: `- q4 `1 K" s# N+ h+ `
6 e2 T; l7 a5 w& V1 b! N% @
PHP文件锁示例:
  1. /*4 E& L) }/ i6 t0 _6 c+ f  _8 v# t% m; t
  2.     模拟秒杀活动-- 商品100件3 S- }" W: S! |
  3.     CREATE TABLE ta
    0 f5 `. y/ o" J
  4.     (8 V, v2 Z  @  g. Q. J$ }9 K! @2 o
  5.         id int comment '模拟100件活动商品的数量'* z; |6 R$ w6 t$ B  y7 A  {
  6.     );  g# ~; k$ X4 m" }8 Y
  7.     INSERT INTO ta VALUES(100);
    2 n5 R& V( X! k% h& |- f- a. i
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件8 W$ J- u& J' b
  9.      */
    9 \6 {& K; e6 t- ^' ]
  10.     $ D$ F' W. v& C4 O0 K
  11.     // 关闭错误报告
    8 f5 }; q4 H' Y2 `. E- z
  12.      error_reporting(0);
    / \1 L* S. _8 o3 z3 s- C- O

  13. $ s( H, A6 Z: |# ~: G; K" R
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    % ~5 K. x! t- S5 F8 Q
  15.     $dbuser = 'root';            // mysql用户名
    ; y' |' j9 H/ Y+ [' L
  16.     $dbpass = 'root';          // mysql用户名密码
    ; N2 U, N& ~+ p
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    0 R: q/ d/ a( Z: b9 p
  18.     if(! $conn )4 S3 A. B0 Z5 P/ ^
  19.     {
    * f  [) L! h0 ~( t$ U
  20.         die('连接失败: ' . mysqli_error($conn));/ X9 Q6 o- X2 c/ [7 W6 j- ]7 f& o
  21.     }' j3 R+ ]7 x; @' m
  22.     // 设置编码,防止中文乱码
    # S  C6 t- a; ?
  23.     mysqli_query($conn , "set names utf8");
    + u7 g9 G6 [4 y$ x0 H
  24.     mysqli_select_db( $conn, 'temp' ); ' U5 I2 D) b+ v  L' p5 t

  25. + f  F( O  w9 g' t5 L+ g6 }  N
  26.     # php中的文件锁 7 D/ _* l; u% \; m2 ]+ u* g
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    & F/ f6 R" b' X- d, R/ u- ^
  28.     flock($fp, LOCK_EX);// 排他锁
    2 ?# |% L! x( g- g
  29.   m; E3 K8 @5 ?% _. M
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ( j  f( b: w5 [0 {  y. j
  31.     while($row = mysqli_fetch_assoc($retval))
    ( i! `5 a) n% z6 g
  32.     {
    ' V2 c( X: z$ z( s  \: T' v* D2 J, ^# a
  33.         $id =  $row['id'];5 @/ z; S+ O+ t; x( h1 A" c# N
  34.     }
    4 Q  n1 G7 _8 R$ C
  35.     % a$ I- Z' B/ E& f5 Z& p
  36.     if($id > 0) ( u: Q$ W; S6 z' Q7 o  {
  37.     { : N' l  w+ V; D
  38.         --$id;
    6 d4 M( t5 l# v6 |
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    # j3 A& V9 @3 P+ ?8 u3 l
  40.     }
    $ e& L* v. s) |
  41.     # php的文件锁,释放锁 1 E) g; n& ?4 F5 w1 @! a% k- I/ ~* d
  42.     flock($fp, LOCK_UN); . z- E# G; M* e
  43.     fclose($fp);* C8 Q* i# _: j; d7 k
  44. 6 q% L% |( R- i
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');' `+ ~5 d+ e7 l. X! y/ P" K
  46.     // while($row = mysqli_fetch_assoc($res))7 \5 n3 O4 \# z
  47.     // {9 f8 A) n$ R# w6 O+ T
  48.     //     $id = $row['id'];
    $ ?# A: a: ]! l, i2 C
  49.     // }' k, U+ ~0 P5 E) Z# n
  50.     // echo $id;
复制代码

4 Y5 \: C( e' T  n3 Q6 f# u7 {5 U/ U, n0 q5 w  N& @4 @3 G
抢券活动实例:
  1. public function envelopeSnatching(){9 J3 v0 j" T! Y: d3 _2 r5 @
  2.         $lingqu = $_POST['type'];0 U# K* O! d6 j9 y, }
  3.         $uid=session('u_id');//用户id$ m# C% X+ f7 i) o
  4.         if(!$uid){8 U4 |5 P7 P- `
  5.             $data['msg']='您没登录,请先登录!';4 {# m& L9 o2 ]' @0 R0 G3 Z  R6 ^
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    9 J- g! n. `# v" V1 U' |% _- T/ m
  7.             $data['msg']='不在活动时间内!';2 [$ S/ r6 g3 o4 z8 c3 `1 z
  8.         }else{+ e' A' x: Q. i0 G; H. |
  9.             $hours=date('H');//当前小时数; k1 [; m- @( M( y9 P
  10.             if($hours > '09' || $hours > '17'){
    . ]2 n/ ?( r, Z. x: {# |/ i

  11. 7 h7 E, l  `" v6 o
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    - ?1 G  e3 b2 C  j5 e8 X+ O
  13.                     if($lingqu == 1){9 t0 J- Q5 ~6 N
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过3 f- o3 K9 r0 x2 B* ]
  15.                         if($hours > '09'){# S7 o: u& {$ d6 f
  16.                             $num=mt_rand(25,28);//优惠券金额
    7 K$ E$ m* O; J+ z, v& y. W
  17.                             $id=1;3 R# z0 P- g' u  [
  18.                         }
    8 g5 o' ?! I0 }  |  l" J8 q& f- x
  19.                     }else if($lingqu == 2){' y! ]! I/ Y; @( t4 d
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();, d0 p1 |. Y/ G6 @0 w
  21.                         if($hours > '17'){* N  a8 w' j; w) X3 v4 P/ Z8 `( }2 W$ K
  22.                             $num=mt_rand(50,55);//优惠券金额
    " }* Z3 `" k+ @/ ?" h4 j
  23.                             $id=2;- Z& A" o8 Q/ v0 x- r8 E: m
  24.                         }: I9 j9 c7 D: V0 f& y. |1 @0 Q/ l+ s
  25.                     }
    ' K+ i7 V$ _* e
  26.                     if(!$id){4 \; {# _: N$ O
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    3 _8 p0 x3 D/ e
  28.                     }else{" _. |' P( K5 ~3 I
  29.                         if($is_lingqu){
    ( ]& [; J6 b" j, k
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';8 }+ S9 v$ h3 I, S( N0 o" u
  31.                         }else{
    2 s' E" U% j9 T3 U
  32.                             //锁表
      |7 T0 I" X' Q" J/ i: M9 x2 Q* i
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
      K& [9 v* C/ L4 m3 \. E
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    5 ~1 l6 C. a. W8 m
  35.                             if($active > 0){, W! r7 e* D" ~( ~/ v
  36.                                 //开启事务0 K& G8 T. ~* k0 `1 s5 H
  37.                                 M()->execute('start transaction');
    & P3 q! p! z  I- t( X7 p1 ~
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));7 g3 w% f5 v0 N2 H
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    / i' J/ b3 Y/ o, u: E; l
  40.                                 $members_preferential    =    M('members_preferential');
    ) v2 o8 c: T, b1 ~* D
  41.                                 //对应投资金额,% j9 q; }  u" X; {* w# N
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));- R) Q0 U6 r; F% W5 L8 n( w, o9 b
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    / i8 I& M! Z) b0 f7 J
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间9 H" _# ^7 I3 g8 |  g8 j
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券' C" @7 p* X& O
  46.                                 if($save && $add && $add2){
    . ~1 @$ Z+ O1 m
  47.                                     //事务提交
    1 l1 F. {4 q9 D! m. q8 p& m
  48.                                     M()->execute('commit');
    ' K! O4 S: T- d, c
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';$ y4 l9 A( p8 {/ n1 K! R2 G
  50.                                 }else{
    % Q, g& x* v3 h; p; z2 r6 q
  51.                                     //回滚
    - w! x; y- a* _5 x# ~
  52.                                     M()->execute('rollback');
    + S; f- \7 c6 z7 {# d- t, @: D) m
  53.                                     $data['msg']='未知错误!';
    & P% G; U! K6 q/ J+ J
  54.                                 }
    $ n4 k6 c8 @9 w/ Z  i1 R7 ]! P. H! G) g
  55.                             }else{: j4 z& L0 a  I8 {4 d
  56.                                 $data['msg']='红包已领完,你来晚了!';
    : j$ G4 i! T( o# S% `' b7 f
  57.                             }# _' o+ S! h: f4 p, I/ k
  58.                             M()->execute('UNLOCK TABLES');
    2 R8 Q0 R7 `$ w8 e4 i
  59.                         }  \9 o& b# W: P+ g; F$ H5 g/ B- v* Z
  60.                     }9 Y, e2 P- B  u% Y0 l
  61.                 }else{
    ; c, |; S. m* R  ~6 D  h
  62.                     $data['msg']='非法操作!';' f: Q, g# l6 \7 g
  63.                 }
    , E% }( v5 z% ~6 ^
  64.             }else{+ |% c2 R! n4 @2 i* E4 L3 ]- }
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    - {) s2 q2 O$ k, D3 X* C6 `6 Y$ M$ L
  66.             }1 x/ K: a! t& L# G* V
  67.         }$ c) }; h/ [! ?7 Q
  68.         exit(json_encode($data));
    2 A  x% {  |0 u7 G7 q
  69.     }
复制代码
: v/ i8 c4 X+ R
( E) }$ U4 w5 a5 n6 |4 p
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 15:23 , Processed in 0.052864 second(s), 20 queries .

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