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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3845|回复: 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://请求的脚本
复制代码
0 m: k6 P3 v8 z  |1 K7 t* u
Mysql中的锁语法:
( w$ y6 @/ e5 x; A! l; l4 DLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
7 Y5 G* w% ^# G/ X! QUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
  v  |, z4 [; f6 DWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
# o2 G% H: [. o% P; @; B: s注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :: k0 I& N4 G: p4 N
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
& E" U% |! K4 w+ a0 F3 L测试时,有个文件就行,叫什么名无所谓
总结:$ o3 K- }* h  Y
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
0 r* e  B8 @, a: @" j0 c- u2 i0 \1. 高并发下单时,减库存量时要加锁0 D6 o- l" o! J& p) O
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    2 T* @4 f( t  t* R/ V
  2.     模拟秒杀活动-- 商品100件7 R, e) Y8 @- s/ w8 [  j3 Y
  3.     CREATE TABLE ta
    ! B( w+ H% ]& r8 u5 K- B& A
  4.     (# q0 C2 g4 N, ]% g
  5.         id int comment '模拟100件活动商品的数量'2 n7 h3 z7 P" S/ z7 R
  6.     );
    # B3 k% z7 ^2 |8 Z, q
  7.     INSERT INTO ta VALUES(100);& f7 m+ Q2 ~# f
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    8 `: K, t! _, s: o
  9.      */ ! k6 s5 _/ K$ }4 P
  10.    
    ; l  E+ b' i- f9 }1 F' j
  11.     // 关闭错误报告) A4 i$ t& a7 L. P- m) Y7 H( a( x
  12.      error_reporting(0);
    5 S! i7 B+ w* f2 n  m7 B

  13. ( j- e8 V6 U. u& ^! B
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址1 u( c5 Q$ t0 a8 Y
  15.     $dbuser = 'root';            // mysql用户名0 R5 @5 k# C9 {3 ?" i7 [- n
  16.     $dbpass = 'root';          // mysql用户名密码
      a' F) \' v0 J! s; N
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
      a7 P% z5 W: U* c& `( I
  18.     if(! $conn )9 j3 z  G+ s1 w* l5 u
  19.     {
    1 S- ~3 v1 E1 q/ f9 P( w
  20.         die('连接失败: ' . mysqli_error($conn));
    : F6 v) Q, S! r1 d  d
  21.     }# b& u" l1 v0 F7 l
  22.     // 设置编码,防止中文乱码& v  A' H7 H( p# a2 f, x
  23.     mysqli_query($conn , "set names utf8");, @; O% ^4 Y" _/ H
  24.     mysqli_select_db( $conn, 'temp' );
    - L& _6 m. U# M6 w: \, b/ N

  25. ' i1 }9 ~0 f5 ~( V! S9 m, j2 Z
  26.     # mysql 锁
    / y% J  u% ^7 ^9 m
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    - @! m% H  K! C9 J6 g
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    7 ]# L! b1 _) _: ~! b5 s; `- |
  29.     $id = mysqli_result($rs, 0, 0);
    + [+ z/ Z5 o0 Q9 g0 |0 f( Y
  30.     if($id > 0) * ^4 T8 _3 V, J- \
  31.     { / h. C/ R, s( z
  32.         --$id;   X" t' N7 B- B: N
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    / K; d5 R6 b0 j. f
  34.     } 1 L. V8 W! F1 c0 l  }# G1 o9 B2 R: L

  35. . l7 {! d7 Q- {  z; i* }
  36.     # mysql 解锁
    , \1 O% p: Y4 W( Q
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ' s! G- Y3 e) x4 q
  38.     //查询解锁后的id值
    % f3 _1 ?: M% l) a& p) F9 i
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ' H$ X! {, h  W+ U# R! l
  40.     // while($row = mysqli_fetch_assoc($res))4 p0 d/ i( M: A" `; X+ J
  41.     // {
    8 E( K, w4 P+ O
  42.     //     $id = $row['id'];1 }4 b  h$ K! D1 P7 o
  43.     // }6 K/ F, s6 C2 D/ j- g$ A+ W
  44.     // echo $id;
复制代码

/ |0 m# Z0 V/ y3 D0 K( q' [$ H% M% I
5 N7 P. u/ Z/ }2 n5 a$ g
PHP文件锁示例:
  1. /*
    $ P7 N+ D. P% e7 Z  T
  2.     模拟秒杀活动-- 商品100件
    7 G/ @& z/ c9 E& u8 y# b. Y- v5 O) S
  3.     CREATE TABLE ta8 U& W- ^# J$ [; ^
  4.     (
    ) _8 T! g$ F% d0 p
  5.         id int comment '模拟100件活动商品的数量', \, w# X2 z5 D, k
  6.     );
    / s4 B3 Z7 w9 f$ c" e
  7.     INSERT INTO ta VALUES(100);
    " F  U4 B8 B9 P8 i8 z
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    * U: }4 E1 z7 w: ^( S
  9.      */ ; ]2 j, h% m4 v  t8 D- m
  10.    
    - @! Y* h* h  t
  11.     // 关闭错误报告
    ( e8 r# K; l4 H5 K# f
  12.      error_reporting(0); 3 O8 j0 z1 |8 @3 u
  13. 7 }4 E* ]  h) B. |. L: F1 _
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址0 A7 b( g- ?: |$ |, f4 G; Q
  15.     $dbuser = 'root';            // mysql用户名
    $ S* X/ I4 S: D9 w8 L
  16.     $dbpass = 'root';          // mysql用户名密码
    2 f- E( |# X2 f' J/ g8 V9 `" ]$ D
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);/ y5 e* r" I6 ^; L4 Y
  18.     if(! $conn )
    , a5 u8 o5 k: O& z% T' P; z  x7 q; u; @
  19.     {
    8 X& x$ k7 I5 U2 N7 K" L- l
  20.         die('连接失败: ' . mysqli_error($conn));
    6 ]0 X7 r  V4 @7 G9 h: p% E
  21.     }
    4 u! t) e1 \5 W; d: T
  22.     // 设置编码,防止中文乱码4 B& c5 M, g; t% I" F& N( V6 w; z
  23.     mysqli_query($conn , "set names utf8");# B+ O$ v' V% ]( m0 p' E
  24.     mysqli_select_db( $conn, 'temp' );
    $ }- R" D3 f: Y; U

  25. ! w3 `; \; U1 J# J/ t
  26.     # php中的文件锁
    3 W. `2 y. R" _' j6 R8 q2 F
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    9 _& c$ L( o8 @0 Q; l& l8 ^/ E
  28.     flock($fp, LOCK_EX);// 排他锁
    1 x, ]  P; H# h7 o2 J2 b0 N! f
  29. & s: j9 k; X( c# n9 e  I
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    1 ?. g' B" t3 s* G+ r* k
  31.     while($row = mysqli_fetch_assoc($retval))
    2 c5 F+ j: b5 l" R/ y6 P, D
  32.     {
    8 H$ O: a7 K0 c/ _/ @% F4 N" V
  33.         $id =  $row['id'];
    8 B0 U& T9 ]# o3 W! K" Q
  34.     }
    * E0 c: g7 e1 `: f. |' U1 h8 @
  35.     $ o. p6 x3 Y  @/ o$ S
  36.     if($id > 0)
    % I2 v* n3 ~. Y
  37.     {
    - k2 d# `7 V0 A# J# r
  38.         --$id; * a1 t: x' |) _3 M
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); ; z2 d# l/ I/ A* [! d: f
  40.     }
    ) R) c+ e- t9 A+ ~$ M5 C
  41.     # php的文件锁,释放锁
    $ j1 Y  S2 T+ Z" `4 n6 k8 z
  42.     flock($fp, LOCK_UN);   W" ~! Q: \3 \, Y  X1 U0 h! C3 e3 S
  43.     fclose($fp);& ^; F& Q; S* }- @  L; Q" R

  44. 2 s& F" Q( e- b& z5 M9 ~) `
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ' Z+ U; c1 E; k" |3 _
  46.     // while($row = mysqli_fetch_assoc($res))& R2 ^7 S* Y* G  o% Y# q
  47.     // {
    4 q0 Q8 B& Q9 v" I* m0 u* h1 V
  48.     //     $id = $row['id'];
    ) o" o  ]6 e3 p# c( [( Z
  49.     // }% D3 \# |& e7 P
  50.     // echo $id;
复制代码

3 g" s1 `$ x- M/ V
# C& }0 Y1 X1 p; I5 }5 H5 e
抢券活动实例:
  1. public function envelopeSnatching(){
    ' N5 w, z. {# R0 L
  2.         $lingqu = $_POST['type'];
    4 @" U& O! ?6 F% C
  3.         $uid=session('u_id');//用户id+ c& D& I4 Y  W8 k' u
  4.         if(!$uid){/ {& P  h" `, l& M; I% x* f+ |* v
  5.             $data['msg']='您没登录,请先登录!';  X) q1 d- T, r( u3 {4 O
  6.         }else if(date('Y-m-d') != '2017-12-12'){# e* P6 z' o3 h# q
  7.             $data['msg']='不在活动时间内!';7 u' ], h  f9 I! v& b
  8.         }else{
    3 ~3 g6 ~( f+ P+ U; ~
  9.             $hours=date('H');//当前小时数5 s  D# M, N4 |. ~/ X1 i
  10.             if($hours > '09' || $hours > '17'){" |7 ~: f: c! A' |6 _. R
  11. , S/ n8 a: c; T& ~
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    5 c; `8 K) G1 d* `8 ~
  13.                     if($lingqu == 1){9 k6 v6 q- P3 x$ O
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过( [* H5 A8 J/ ^0 B; j7 T
  15.                         if($hours > '09'){
    ' q" d* e# s; d7 J7 y* S. P9 Y
  16.                             $num=mt_rand(25,28);//优惠券金额
    - r+ M$ {, I% X! P
  17.                             $id=1;3 y1 J' d7 ^) B. Z/ o6 ^
  18.                         }
    & _4 m* c) s7 g/ ~6 t% ~
  19.                     }else if($lingqu == 2){+ @- P1 E7 O" q$ w1 O
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();$ w' F) M& ~; B6 n
  21.                         if($hours > '17'){
    6 X, b% @* E0 V! k. |, U) f1 r
  22.                             $num=mt_rand(50,55);//优惠券金额
    ' J  J# F$ j! Y4 N( O% X9 R
  23.                             $id=2;6 H% Z% k# R, c. r. `  v0 V
  24.                         }' l$ w6 j' R1 t) f
  25.                     }
    . l% x8 y+ L) Y
  26.                     if(!$id){
    3 ], ^. B) h+ Z, _  H& I+ v
  27.                         $data['msg']='时间还没到,晚点再来吧。';4 i& h( `- k3 o: o
  28.                     }else{
    7 [! P$ p; p- @% @' d: u
  29.                         if($is_lingqu){
    9 K6 `3 w2 j0 U$ }
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';# G% l* h! I! D& U) m$ P" ?% p
  31.                         }else{, d: S* {9 W* j" A# c
  32.                             //锁表
    ) p9 z% D1 |1 E& U) R% D: |1 F
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    : P+ m; H% ~) |: l; o1 _% D
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();% Z9 r+ m: n9 }  c+ o
  35.                             if($active > 0){# h# R# Q& F& H) s/ |' T1 P
  36.                                 //开启事务! o3 f9 ?) D( M
  37.                                 M()->execute('start transaction');
    7 M  e7 u: B  c5 v/ p+ P
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));' z% R. L5 e3 [, W1 k! V
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    ( l7 ?' n) U2 M: }8 b, F! e
  40.                                 $members_preferential    =    M('members_preferential');/ M5 N7 a$ u! O' Y2 C
  41.                                 //对应投资金额,  V1 c" v2 j- b$ e" j. J' L
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ( o- X5 W' {4 h5 r! r
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');: Y2 e4 J5 \7 q- ~* r# r% w
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    4 Y$ @! S8 E. D/ i) A& |
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    - N" h$ N! y4 {
  46.                                 if($save && $add && $add2){
    ' A9 {8 S8 k. ]
  47.                                     //事务提交$ V/ C: {/ U# X- E8 t. V( S
  48.                                     M()->execute('commit');
    2 U, ?' Q' X( w) }* d* M
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';1 h; m/ b* T* u* }1 ~1 l  P+ K6 U: @
  50.                                 }else{1 B$ @& L6 K5 ~" ]7 d5 G+ f
  51.                                     //回滚
    ' g) ~; m3 z9 h/ N( ^* Q, r( W
  52.                                     M()->execute('rollback');
    9 l% E  k5 N1 E; ?
  53.                                     $data['msg']='未知错误!';/ p( R9 b( B; @& T6 Z" E0 u
  54.                                 }
    # H" n! S0 [% S. q1 g- ]# l
  55.                             }else{; |3 h( o8 j( s8 c8 S
  56.                                 $data['msg']='红包已领完,你来晚了!';* K3 q0 k3 G" i
  57.                             }
    ( F  g4 `' v2 T( W8 O& i! G) @
  58.                             M()->execute('UNLOCK TABLES');/ Q) J6 c" d8 {( f6 \* H
  59.                         }
    % C6 @6 j% Q3 \! H8 d5 _
  60.                     }
    ( ?3 U( {  g/ q# n9 v! n' C( w
  61.                 }else{
    ; H- @% `3 G* y3 ^& C
  62.                     $data['msg']='非法操作!';0 T" `( Q  v" L# u1 w, a
  63.                 }
    $ P0 B6 Z" h. t8 X0 [: ]$ ~
  64.             }else{
    4 t2 G* z1 C* k+ v- M
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    1 l$ j; A/ _. z" o. o
  66.             }
    / c1 I) p% ]( X6 R. b, R! L
  67.         }/ j, O% w; Q$ ?) P5 j
  68.         exit(json_encode($data));
    & B* B5 U. V" q! N, F
  69.     }
复制代码
, n; j& K% w; T+ p0 X" P
9 `+ E/ g0 N2 R: G8 `7 v
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-7 12:45 , Processed in 0.145633 second(s), 19 queries .

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