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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8359|回复: 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 A7 E( k7 t; i8 g( z7 [
Mysql中的锁语法:
# q9 b8 U" u5 }8 z: r( J# ^. {LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】$ H. j! ?7 T; y- C7 W
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表2 p" I8 B- t, }( _+ s" u* D1 f
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
1 ?9 [# v7 _7 h注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :: K1 i9 k  x, ^0 T1 r% Z9 r" t- J
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
( y6 ]' U5 V& e6 [/ `# d' M' i测试时,有个文件就行,叫什么名无所谓
总结:
% r. C5 N( E0 a项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
+ y; e4 X9 [! h' i1. 高并发下单时,减库存量时要加锁
7 T4 h) R- C1 _1 D2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*9 j8 P7 W& y' D
  2.     模拟秒杀活动-- 商品100件
    $ W7 V$ G# ^" g3 x, x8 J# V, v
  3.     CREATE TABLE ta' u/ S3 D. Q+ ?! n
  4.     (8 q4 U% m) ~! S
  5.         id int comment '模拟100件活动商品的数量'
    / g% I: q% n5 `6 O9 [4 A1 m6 q
  6.     );; R: v" v" j8 ], H  \! D6 r- ^: f
  7.     INSERT INTO ta VALUES(100);7 s- D) e) Y7 V, @6 g. F9 {
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    4 g, M! T" t! q# R9 C0 M
  9.      */
    ) m- x: ~) k: l, {! F! ~% H
  10.    
    5 }6 `% D  H' ]0 p; n
  11.     // 关闭错误报告' b9 {4 |) ?& ]! C+ t3 T3 K# F
  12.      error_reporting(0);
    " }2 e  W) H7 ~7 C

  13. , F+ t7 ]9 R. e9 X5 y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址4 ?$ T3 C4 O  U6 v" ]3 |
  15.     $dbuser = 'root';            // mysql用户名
    4 h- {. }- G  @' e  b) ?% r; \
  16.     $dbpass = 'root';          // mysql用户名密码
      M6 t8 Y3 f. f# J4 s( g
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    0 H0 |8 [8 L% e5 R* g2 k
  18.     if(! $conn )* ^- G( h2 G* [! k4 x
  19.     {5 x: }+ B# G! x/ p  i2 n( w: v% f
  20.         die('连接失败: ' . mysqli_error($conn));( O2 K' ?' c5 P
  21.     }
    8 d- v. n2 `! i% F: F! [! n2 k
  22.     // 设置编码,防止中文乱码6 e7 O. i2 U) o& m6 G
  23.     mysqli_query($conn , "set names utf8");
    ( Z4 w. i% J& ~& q
  24.     mysqli_select_db( $conn, 'temp' ); , R9 r3 M. Z3 @$ {  F- n: c/ i; F
  25. 1 H) m3 `' K* D' I. Z
  26.     # mysql 锁
    , P4 g' o; |% T8 |- H# j
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 " D: a% }  E8 y
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 8 T5 C6 I- }6 @9 t  u
  29.     $id = mysqli_result($rs, 0, 0);
    " V1 E& a0 J; G( ~# }# [1 J
  30.     if($id > 0) 7 `" d* Y+ \# G& A) K' v
  31.     { 6 ^- j" K7 q; I% i" ]- M
  32.         --$id; 2 f; O2 q: }& g  r% q6 _5 {* S5 d
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); $ \# r! b) d( S" Y
  34.     }
    ; Y! k+ o* l) u

  35. ! Z. H0 a2 W5 q) g' j1 N  c
  36.     # mysql 解锁 : Z. D- Z0 }5 B" _9 _7 L+ M
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    2 H& {& l8 D1 z% o' b  E1 b
  38.     //查询解锁后的id值& H% v- ~: t5 C" l) ^, P9 \" K
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ! v9 z; J. Z3 q$ C$ t' f
  40.     // while($row = mysqli_fetch_assoc($res))
      X$ o) T7 a7 |  j3 ~
  41.     // {
    : e: l# M; y6 K0 h6 L
  42.     //     $id = $row['id'];
    ! w( @# H7 @  _; s; W1 n9 a; i
  43.     // }9 W2 w7 x6 {- M
  44.     // echo $id;
复制代码
# r7 _( d3 P* P9 e" q7 Y& i
* R! I/ N; H. W! \
' v9 P7 p0 Y6 k: M
PHP文件锁示例:
  1. /*
    4 n; I8 H( L! `1 |# m) u
  2.     模拟秒杀活动-- 商品100件
    9 X5 _/ G  }* g% x% m
  3.     CREATE TABLE ta3 v, o6 a9 c" g
  4.     (
    $ u# [3 K: c( V. _$ m. J1 t
  5.         id int comment '模拟100件活动商品的数量'8 H. v* v( {- G8 m8 _: ^( s
  6.     );  ~& y1 B# E1 p: Z! o
  7.     INSERT INTO ta VALUES(100);' T( I( H3 u( h/ q% j
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件: d3 w2 T7 k  W3 D
  9.      */ 6 \7 k. k! ?. q9 E( o2 x6 s. x
  10.    
    9 a5 ]/ K; u: @/ m
  11.     // 关闭错误报告
    , a- U$ e. v6 V9 Y9 R( Z
  12.      error_reporting(0); & d, t, ~* b. J8 i/ d) ~/ ^1 q

  13. ( V8 h+ Y7 [* i$ y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址: R- m& E* O! f, f. I- {- x+ L1 r
  15.     $dbuser = 'root';            // mysql用户名, G  j6 r8 L& [- C) b/ V
  16.     $dbpass = 'root';          // mysql用户名密码
    # w9 L0 m  R: z4 o$ D" g
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    2 H& |$ i+ A8 L  W. U
  18.     if(! $conn )
    7 @2 {1 [+ V) n2 q8 ^9 e0 S( w; x
  19.     {3 Q6 F8 E' w( z+ u( `5 ^- z
  20.         die('连接失败: ' . mysqli_error($conn));
    1 y( B! j9 {. k- g
  21.     }
    . p7 {, d2 o# U2 B# e  z
  22.     // 设置编码,防止中文乱码
    : k  A1 T+ O7 D" l8 j# J' J9 _
  23.     mysqli_query($conn , "set names utf8");
    ) |6 I6 `* d8 J* B4 Q  p1 t
  24.     mysqli_select_db( $conn, 'temp' ); 3 }, G) `0 m1 D, L+ ^: \0 H

  25. " ^# ~. c7 M" I& r
  26.     # php中的文件锁
    & f" W$ r( s( G! ^
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
      f0 B1 c0 \3 p" p6 D
  28.     flock($fp, LOCK_EX);// 排他锁 * u1 s. \$ q! `2 W) M. ?% |

  29. 6 ~' k8 V! p. V- Y% A" f
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); ' Z0 ~' W  [8 ^' o. p5 r: H
  31.     while($row = mysqli_fetch_assoc($retval)); ?5 o5 d. D) P( ~
  32.     {7 e( g! T$ d' p1 A9 J! G, {
  33.         $id =  $row['id'];
    : E5 m5 d) ~8 f, C5 L3 K4 {: h2 i
  34.     }6 S0 t, J9 D( e9 S
  35.     * x- V/ i$ I0 h9 N
  36.     if($id > 0)
    $ Y/ m4 l, ~( [- n7 `/ f! p, |
  37.     { & q' A7 U' T6 k  ?7 N% R
  38.         --$id; - x, `! V. F9 {8 D, L
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 1 c/ i* l3 f. r
  40.     } / ]: w2 e+ B9 i; M
  41.     # php的文件锁,释放锁 ; w+ I- x  ^1 z. b) {
  42.     flock($fp, LOCK_UN); 6 {0 e* S# t1 h2 W+ u
  43.     fclose($fp);9 g1 B% D9 [+ y; R& b4 F1 F7 d

  44. ; u5 Z  n' n8 T
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');! K# h! Q" |* [3 o( `' F8 K
  46.     // while($row = mysqli_fetch_assoc($res))
    . z) y% C4 E- Z6 T* f1 c
  47.     // {, B; g1 j' m  n( z' g9 J
  48.     //     $id = $row['id'];
    6 g$ }% R4 ~4 P1 e7 m
  49.     // }# {1 f% ]+ e' q+ E
  50.     // echo $id;
复制代码

; f7 T+ r7 j* U# R
2 p8 B7 `* x4 i7 H
抢券活动实例:
  1. public function envelopeSnatching(){2 n# p1 r7 r6 _1 T% o9 C. ?
  2.         $lingqu = $_POST['type'];$ O4 Y3 q! e$ _; t* E3 `
  3.         $uid=session('u_id');//用户id, b$ a( M& U0 o9 R8 ~  E) r
  4.         if(!$uid){
    : g$ j8 h% N  F9 t+ y
  5.             $data['msg']='您没登录,请先登录!';
    ! A# Q5 o% }5 H* K" Z; k2 ?1 p
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    6 q# Q# T' c2 M$ U3 s* c9 |
  7.             $data['msg']='不在活动时间内!';
    / W4 ~7 R) ~+ }1 q& k
  8.         }else{
    + ?) Q/ q4 X) ]# o' L
  9.             $hours=date('H');//当前小时数
    " c) a3 \! ?4 ]8 [, w6 B
  10.             if($hours > '09' || $hours > '17'){1 [/ }* s1 E; z' A9 @  \
  11. . |$ Q* v, f/ c+ o8 i# L
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的4 ?* ]7 ]; X" j8 [+ G
  13.                     if($lingqu == 1){: V8 j: L2 R( W& b5 |' k
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    1 s) Y+ P4 O! _; ^% `" p# K, m
  15.                         if($hours > '09'){
    6 |% P* }9 ~8 \1 q1 l/ d3 P
  16.                             $num=mt_rand(25,28);//优惠券金额
    ! l* m' o! q: c0 V* L( Y) z, x" d
  17.                             $id=1;7 K! P5 S$ A: c, ~$ G9 [
  18.                         }, [9 Y5 O3 ^8 N' a8 V, A
  19.                     }else if($lingqu == 2){) X/ [; i! `5 w$ t/ z
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    ' U5 `$ c* j9 \2 B7 ]2 W
  21.                         if($hours > '17'){9 _8 g0 ]: U7 v- R+ g1 A8 e
  22.                             $num=mt_rand(50,55);//优惠券金额
    ( C0 D4 ~7 G7 C7 n
  23.                             $id=2;6 ?6 x% ]$ k/ |' S
  24.                         }( A$ m  Q1 ?' m' O, d# |1 P
  25.                     }
    5 _4 U& g8 h, E" W% m9 w7 q
  26.                     if(!$id){
    0 E$ T0 W' `  a
  27.                         $data['msg']='时间还没到,晚点再来吧。';4 a' ]* ]( \9 h) x
  28.                     }else{
    3 ~& t% {9 C2 W: L8 O1 Y% K0 r) Z; M
  29.                         if($is_lingqu){
    8 Q6 ?* [6 V: G+ b
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';' [; E1 S1 d% Z) S& P9 m
  31.                         }else{, m  f3 M8 a5 i
  32.                             //锁表3 O3 }2 [( q  N9 O  U6 {& M
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    & T  s- H9 ^5 J$ p( j$ Y9 B
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();! C; s, P/ x/ N  P4 `& h
  35.                             if($active > 0){
    # j9 r. P; @: R0 X, W
  36.                                 //开启事务! g# r/ J# L. A' U) M' k
  37.                                 M()->execute('start transaction');& n5 U3 U. v. ?1 M5 [, E
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    " \8 l/ q7 E9 u, y
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    + Z8 a1 T: m2 r: }; `' ^
  40.                                 $members_preferential    =    M('members_preferential');
    0 {! }" c# A6 K
  41.                                 //对应投资金额,$ f  _& C1 ]) G* {2 D
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));3 B9 r; k1 }" ^: R
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    $ j$ M- W7 c; L! P
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间3 C7 e; n: K8 y+ N
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券# d7 O/ q" G" |3 c6 E9 N3 l- k
  46.                                 if($save && $add && $add2){7 D, m4 [8 k  d8 {5 [' z2 d% g
  47.                                     //事务提交- d2 z  a8 B2 u6 @  b% _
  48.                                     M()->execute('commit');  y  F, q' H& B4 i9 b
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';9 b/ j1 ^: w3 K$ A/ g$ K: N
  50.                                 }else{! H8 V# X" C( z8 X- ^- ?. g( X
  51.                                     //回滚
    9 Y5 K% ?. b% k% x  O
  52.                                     M()->execute('rollback');. b2 i, t0 s3 z, m1 m3 @- q
  53.                                     $data['msg']='未知错误!';
    - @; @$ O8 v2 o1 f( A; U5 V  c
  54.                                 }1 `+ }8 K% Q/ r  I
  55.                             }else{0 D/ P. e. o# O9 y; u
  56.                                 $data['msg']='红包已领完,你来晚了!';
    ! n" v' {1 Y% n
  57.                             }
    + Y" ~1 b; b; O
  58.                             M()->execute('UNLOCK TABLES');
    ; l. K9 V/ n6 B9 `$ k& {3 A' l3 `
  59.                         }2 S& ^( v- K; ?( f% |% i
  60.                     }
      n, ~- B0 T' u6 I
  61.                 }else{
    $ h" D+ ^9 u  ^6 Q6 j" b
  62.                     $data['msg']='非法操作!';0 Z, O3 g8 s% p/ l
  63.                 }% w$ |+ U  a& z$ ^% Y
  64.             }else{  a8 A; S0 I; V8 k6 W1 h- q: {
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';$ @( J9 I' k+ ^3 g% _% E
  66.             }
    5 t& D9 A0 ^0 y3 ]% A
  67.         }' R, L% ^3 f4 _' |, a0 Q
  68.         exit(json_encode($data));
    / s: j5 u7 o$ p# z% _4 ~, d: M. k
  69.     }
复制代码
9 q  C* K; z. H- y
$ D6 x( u) E2 g6 ]( p
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 17:19 , Processed in 0.062569 second(s), 20 queries .

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