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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8655|回复: 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://请求的脚本
复制代码
) e' p( Y  ^3 t& O8 m
Mysql中的锁语法:& r; I- a& V$ s! y) Z# v0 y
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
2 [6 ?2 p" R% a5 A, O1 \9 o; BUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表" o: i0 @1 v1 e$ t3 I
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
- ?9 a& E& B. V$ Z. d) T& s注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :% i. c" G/ W* Y) J
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
- S$ s/ A% k4 S+ U8 z" `7 Q测试时,有个文件就行,叫什么名无所谓
总结:  }* n: C- p# t) B, p6 }8 P" Z& U
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:. A7 g- o2 {1 v2 F% T' B: @
1. 高并发下单时,减库存量时要加锁' E) U0 e4 Y% I* d* v
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    2 ~& h8 p1 h" h! g( u+ L* q8 b0 w
  2.     模拟秒杀活动-- 商品100件
    6 ]; I0 D3 H4 P. |
  3.     CREATE TABLE ta
    3 Y& D3 t8 N/ t
  4.     (
    ; |# J" u# Y0 p% ~, v, e5 x9 v
  5.         id int comment '模拟100件活动商品的数量'% @' n# K: q/ d% i
  6.     );" Q% z+ d* c  ~5 @
  7.     INSERT INTO ta VALUES(100);
    ( i- H, q# K9 r0 I% q. l7 N* {
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
      F: n2 o4 X% h( t
  9.      */ - e' L: W- h# ?+ M! S0 g
  10.     8 x( w! C' h4 D9 b& @
  11.     // 关闭错误报告, s% g7 G# D) Y7 K. I
  12.      error_reporting(0);
    " [7 }% B* S& Z

  13. * o+ n. Z6 l) S3 L
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    & |9 N. X' W8 L( [1 f( F; F8 z
  15.     $dbuser = 'root';            // mysql用户名
    ( k; l/ e1 C$ n2 y0 q
  16.     $dbpass = 'root';          // mysql用户名密码
    6 k8 v& a* D1 Z; d
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);9 k4 I; X' k/ Q, @% b
  18.     if(! $conn )
    & V3 `9 Z# @; B  D
  19.     {
    # Y, {2 R* b; M# _
  20.         die('连接失败: ' . mysqli_error($conn));
    . G8 G; {  ]! \4 }' p
  21.     }, Z; A) a* k1 A1 f+ `4 p+ N
  22.     // 设置编码,防止中文乱码
    % E3 u4 s2 c7 L( X
  23.     mysqli_query($conn , "set names utf8");' ?% q: h& H0 ?! C2 k
  24.     mysqli_select_db( $conn, 'temp' );
    2 e+ H$ n, E, `

  25. 3 p/ o6 a' n, {' ~' ]+ U) o( t
  26.     # mysql 锁 ( s6 t$ W# }: I0 t0 u" x/ j
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    , R- [  O( M$ G, C2 n3 V) I
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    4 r! u' p- N2 a; T" k  e7 T
  29.     $id = mysqli_result($rs, 0, 0);
    4 n) `5 n. W) Y' |* H& K# A7 g
  30.     if($id > 0)   l: h$ {# j8 Q2 V/ N
  31.     { * J6 U. e# ^6 A: J/ {
  32.         --$id; 3 r, k8 q3 M0 i; E
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); ; Y0 w. q9 V3 `9 `# r3 A
  34.     } & z9 Z6 \) ]% N* v% d! q  w! \

  35. : v1 p7 ?5 J) L, M) h8 L
  36.     # mysql 解锁 4 r; c: B3 A8 l" p% t1 y  R' y
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ( V; y1 G. A' A1 F/ _6 E3 Q
  38.     //查询解锁后的id值
    % e; S3 J- Y! c& j$ B
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    1 R3 q( ^5 d6 Z* y
  40.     // while($row = mysqli_fetch_assoc($res))
    ( |* b3 N" t! O. _2 O3 _" T
  41.     // {/ x# G4 y' X4 I& W, I
  42.     //     $id = $row['id'];! q8 C, U8 K6 C7 c% n
  43.     // }
    0 }: H1 I2 h$ a
  44.     // echo $id;
复制代码

- e, W! K2 `' Z' _" R
1 z. r+ S" W7 z7 k
, f1 t7 }6 b3 G0 o3 G
PHP文件锁示例:
  1. /*- G* X5 V+ d- C, `6 k- x1 t5 C! f
  2.     模拟秒杀活动-- 商品100件
    5 S0 Z9 N7 `: g- C4 h
  3.     CREATE TABLE ta
    $ R5 @! h2 T$ o8 K, p
  4.     (
    ' O1 ]1 K6 g# r) L6 e6 u; U0 v, L
  5.         id int comment '模拟100件活动商品的数量') j  y$ _. c/ O/ M
  6.     );
    . R( b# K6 k9 f, b0 h, I) D) I
  7.     INSERT INTO ta VALUES(100);
    ) U4 k- V4 d  @: H8 S
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件3 r. |8 k& M, O7 f( \
  9.      */
    * X( C! U6 b. f4 n1 x& Q
  10.       O+ C3 o# ^; B! {$ v/ ]1 R
  11.     // 关闭错误报告
    ) |4 m2 k4 ], v) W. k
  12.      error_reporting(0);
    ( g' [+ \. _' q. Z; f: F* ]
  13. ! U7 r6 m  P1 d
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址" _6 K9 i9 ^5 j9 v: ]
  15.     $dbuser = 'root';            // mysql用户名( {4 A; A" U# i' }
  16.     $dbpass = 'root';          // mysql用户名密码+ P1 l& r. d& O/ w9 s1 U9 }, c
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    " A# s9 A4 O& i" s: U9 Y
  18.     if(! $conn ): N: f! B) S6 N) U
  19.     {
    2 J: ?( J: x: ]* s  l3 D# h1 g
  20.         die('连接失败: ' . mysqli_error($conn));
    , S- s0 a5 D& K4 g  J- a( r8 z4 ?
  21.     }6 Z: @7 |$ Z. ^% @
  22.     // 设置编码,防止中文乱码
    " L3 O( @4 f# p1 j0 W7 Z
  23.     mysqli_query($conn , "set names utf8");1 D0 E0 F2 R# u" m# X
  24.     mysqli_select_db( $conn, 'temp' ); 1 K: y: a7 _4 T% Y$ n- i

  25. . C: [, Q9 ]! i+ w; {/ R
  26.     # php中的文件锁
    0 {" z( U, O/ w) A5 t
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    2 o% o( T& V1 M/ A4 d& m
  28.     flock($fp, LOCK_EX);// 排他锁 ( ~+ J1 E9 d4 B! T1 Q1 S

  29. & t$ f2 P4 J* z9 F
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); . q0 Y( U' n9 ]4 b# x
  31.     while($row = mysqli_fetch_assoc($retval))$ N5 K. ?4 ^: m9 r2 i- W: z# i0 S( z
  32.     {
    5 m* Y; }6 O: A3 \6 V2 Z
  33.         $id =  $row['id'];4 _0 y% n6 a+ V3 u/ \
  34.     }
    8 Z. K. u: V1 v7 N- \5 z2 q; C" i
  35.    
    # d& i/ H- N& q1 M6 O$ J+ o6 @
  36.     if($id > 0) 7 M( I9 J0 e. @5 n" Y& [
  37.     {
    * R/ `2 c  k+ |: Q  k' F; m- q
  38.         --$id;
    - a3 ^. b- R! M
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); # ?- z% e7 L& v# {' c
  40.     } 8 ?, D8 t0 N5 Q! Y/ U8 a  j1 l
  41.     # php的文件锁,释放锁
    ; m; V1 j: L+ V8 x3 T
  42.     flock($fp, LOCK_UN);
    , o& p0 V, ], b0 z+ O6 Y/ L
  43.     fclose($fp);5 W7 }* q" D+ A3 m; Q

  44. ; z9 N- Q6 i$ z" G
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');4 G; X+ j7 ?: I! j4 b
  46.     // while($row = mysqli_fetch_assoc($res)): g5 A" s) m/ Y! y
  47.     // {
    ; ~5 J& L7 V5 V% j) `5 N" `
  48.     //     $id = $row['id'];
    5 b& N6 R' h# D4 A- b
  49.     // }
    4 C6 \' `7 q& s: S4 b
  50.     // echo $id;
复制代码
9 ]: }/ K) N& i3 p+ X

$ b& f2 t% ?+ g! X; O
抢券活动实例:
  1. public function envelopeSnatching(){" p; ~; h" p# A( K' p! _
  2.         $lingqu = $_POST['type'];% @) S: k& N$ \3 C& V. l8 [  }) l
  3.         $uid=session('u_id');//用户id: Q; P8 M8 b& a' i7 |4 }
  4.         if(!$uid){1 w% i* l" G/ |5 g
  5.             $data['msg']='您没登录,请先登录!';
    0 }0 I/ a+ ^# V7 W
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    5 w& h. g: Z* ]# n
  7.             $data['msg']='不在活动时间内!';
    - ], Z( T; Y% @( z8 `
  8.         }else{4 k+ A8 N6 ~7 j
  9.             $hours=date('H');//当前小时数: |/ Q9 }) u4 _! ~3 x( `, H8 P9 A
  10.             if($hours > '09' || $hours > '17'){
    6 `& \1 g7 D, p7 C9 W) f
  11. % R: W* D% O2 x" h1 `
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的% b8 K+ q2 |! t+ g5 k
  13.                     if($lingqu == 1){
    * |. r, Y. ^. t# h
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过5 a7 N: A* D$ _- G/ f
  15.                         if($hours > '09'){! ]/ H: B* C9 Y- h8 [
  16.                             $num=mt_rand(25,28);//优惠券金额
    3 g& c5 a' J5 w* R
  17.                             $id=1;: t5 ~7 n' ~! ?
  18.                         }
    2 a2 ~# ^, j1 T9 m6 L/ j
  19.                     }else if($lingqu == 2){1 a; _2 c4 [5 e# M4 P' }% R
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    ; a3 m) `. O8 ?7 ?: f; L7 k7 A' ~- ]
  21.                         if($hours > '17'){
    . U1 o4 x0 v" |5 V
  22.                             $num=mt_rand(50,55);//优惠券金额  V" E6 P/ K- D7 z5 `% z$ e) u
  23.                             $id=2;
    9 E: M$ P& v0 f1 w) v% `# A
  24.                         }4 t( A( h- I' \& }. K, o7 L
  25.                     }
    5 b: w' w2 c4 H. W; T# x
  26.                     if(!$id){
    ' {. H. J) L) E1 H( _- K' ]
  27.                         $data['msg']='时间还没到,晚点再来吧。';$ n7 k# x" m3 i0 s
  28.                     }else{
    0 v9 X* G' N2 f0 e/ v& S3 H
  29.                         if($is_lingqu){" v0 f* e5 T  [
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    ) s+ x8 U0 r3 \3 C, }. [+ r& C4 M
  31.                         }else{
    & |- ^( _5 L% w3 o4 @) m8 U1 p' u
  32.                             //锁表
    * Y) S: o- K' w+ C8 [2 n; @) b
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    ! C/ r6 Q! l9 R- B
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    8 r! Y+ y$ o9 C" ]4 M8 R  E, d' \
  35.                             if($active > 0){" D& q$ n3 m4 I, q9 n; p+ o
  36.                                 //开启事务
    " ~2 ^* L! u  Y! d3 m" |
  37.                                 M()->execute('start transaction');6 \6 c  B$ c' o6 Z! k; `
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    " M2 f" }/ A- W1 l! J
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    . f# w" k, K; R3 [# b* L
  40.                                 $members_preferential    =    M('members_preferential');
    ' Z( t. U8 p) B5 A5 L
  41.                                 //对应投资金额,
    # s, D- l; g% n9 g1 z; G0 ?8 j# \" n
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));% ?0 @2 |' s6 M% q# W* b7 P
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');* {1 ]; w( e  b' y% `
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    / Z8 V# R, Q7 ~* L/ J8 ]
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    2 g. ~3 j$ t. ^( T# Y$ L/ S
  46.                                 if($save && $add && $add2){
    % Z" Y9 I) ?5 p/ O
  47.                                     //事务提交
    ( c4 A6 _5 y$ a) P& D8 D4 o3 ~) v- s
  48.                                     M()->execute('commit');
    - R- z0 F. ]1 o+ g( e# z
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    8 Q  O' _  N: h, i* w0 j
  50.                                 }else{
    & u& B' i* x2 ^: \  v4 m
  51.                                     //回滚5 v8 H# ~% |) m, t
  52.                                     M()->execute('rollback');
    2 B9 T, D. S8 B8 j% M
  53.                                     $data['msg']='未知错误!';3 R6 c' c( F# p, f+ t% s
  54.                                 }: H% z0 k. L& I$ X+ [4 V
  55.                             }else{
    ( X$ W+ L7 O, G4 G
  56.                                 $data['msg']='红包已领完,你来晚了!';' ?( ^) P+ G- U! Q1 \
  57.                             }, h+ b2 D- J  R1 i6 q% P: Q7 R1 R1 N
  58.                             M()->execute('UNLOCK TABLES');
    + f) e; g$ o0 J, C5 _
  59.                         }
    & {' o& \$ W6 S  A. [1 U+ v1 d. X
  60.                     }
    4 w; _! @" d) W, ]! ^$ ]8 y
  61.                 }else{. C/ k7 V" c8 \1 w" u9 o
  62.                     $data['msg']='非法操作!';
    # v/ C/ z: a8 I( q4 a
  63.                 }6 ]; z6 k9 P0 E& g  I: R1 M
  64.             }else{  `8 Y* e: O# s
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    0 }% Y* o) v5 C3 R! S
  66.             }
    3 z$ c0 u& G) M* N4 ?7 N5 L
  67.         }
    , X, Z& v7 C( n( O
  68.         exit(json_encode($data));
    ! a/ V- X8 T$ q& o+ {! A
  69.     }
复制代码
' k8 B1 z1 V. R

) b. M6 u$ G( j: Z" Y& f" f2 v% m
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-4-30 16:14 , Processed in 0.064948 second(s), 20 queries .

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