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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 6202|回复: 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://请求的脚本
复制代码
' O' M4 ?4 ?5 I" U# _6 S
Mysql中的锁语法:
" s7 G9 F' `0 _& rLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
0 d2 A1 Q) Y# G* T+ P# TUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表3 G! I& S( B) |( }% i
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
3 X( G; }: r9 o0 g4 N- ~9 C注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
5 N+ l( q- O' B3 d7 l文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
, a" j6 i2 t# Y& S0 C( q测试时,有个文件就行,叫什么名无所谓
总结:8 H- j: t; m2 i6 j9 f
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
* m. J3 _! ^9 _6 Z) m1. 高并发下单时,减库存量时要加锁
- @+ U/ s3 Y$ S8 C* J9 \2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*) A: P( C* D4 H2 c
  2.     模拟秒杀活动-- 商品100件' n& `( d" T6 U1 r+ G
  3.     CREATE TABLE ta1 p" l: [% k( T1 @- y/ G
  4.     (2 B3 i9 g; l! K- r+ g
  5.         id int comment '模拟100件活动商品的数量'
    $ H& \0 z% p* V. K8 U& J% A' J
  6.     );/ ?4 _' s& \! t* j2 x  ]1 P/ o; W
  7.     INSERT INTO ta VALUES(100);
    6 w( |& ~. @+ M. E0 x
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件0 v1 a% I; q1 n# |
  9.      */ 0 i- [  `/ W* d
  10.     6 w0 W+ b' l! n& y7 \7 X6 O
  11.     // 关闭错误报告6 D6 w. G6 j6 M. L+ q/ ~
  12.      error_reporting(0);
    7 d0 o5 \2 X& b" T  ], |" g

  13. 9 v- y7 _0 e5 \( U, K
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    9 y* B7 l; q2 T' u- t0 N+ K- _
  15.     $dbuser = 'root';            // mysql用户名8 S) K& h/ c* |* f% N) o
  16.     $dbpass = 'root';          // mysql用户名密码" P3 G0 _; h# b4 D7 Z( o2 j
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    / c0 I+ I3 I" ]5 Q
  18.     if(! $conn )
    9 L8 V! c, U; _0 V! L& d5 G
  19.     {
    3 j" X8 o) l) H3 b. {
  20.         die('连接失败: ' . mysqli_error($conn));0 D0 \3 C4 Y9 `9 }4 W9 W- c; r
  21.     }
    # K  [8 B0 `6 K9 l
  22.     // 设置编码,防止中文乱码
    4 N6 s* j$ `4 c, @
  23.     mysqli_query($conn , "set names utf8");
    4 M, \- P6 {) q5 E1 |+ W2 l. g. _
  24.     mysqli_select_db( $conn, 'temp' );
    + u" p+ E! F3 l
  25. " V& Y1 |: {9 H0 T/ F4 A
  26.     # mysql 锁
    1 c( S6 J" V' I) K7 i
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ; L* O* A& R$ \9 a* c  G) W, Q7 ?
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); * c) l  ]/ g4 a! L. Q7 o
  29.     $id = mysqli_result($rs, 0, 0); 6 r5 ^4 V) M* Y6 S
  30.     if($id > 0)
    7 z, b8 ?4 K7 J4 c8 Y6 J: x
  31.     {
    1 i: ?8 x7 T. o3 A8 r7 _  Y7 d
  32.         --$id; * E* y" R+ Q8 H4 Y& p9 B: N- y
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 5 v+ [/ f; ~( M1 H: u+ ]
  34.     } / x7 @/ u& g& ^9 H/ B5 i" ]/ y
  35. 4 |8 A; Q: B, O. s7 P& w% w1 w' X# j9 J) N- D
  36.     # mysql 解锁 / L9 J4 q  E. W% m$ ]- k
  37.     mysqli_query($conn , 'UNLOCK TABLES');1 f; @: @8 `# r* R
  38.     //查询解锁后的id值
    , [( [- }% r! {$ i* F
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ( ^) @  \* A7 t+ E+ \+ Z( J
  40.     // while($row = mysqli_fetch_assoc($res))
    9 _3 }2 m. {' v2 S* G5 T
  41.     // {
    / ^$ A/ m$ i/ T
  42.     //     $id = $row['id'];
    * n, c4 k/ L( n# d/ x
  43.     // }
    $ u1 Z* o) z4 Z) _
  44.     // echo $id;
复制代码

: ^9 d8 ~  O; E( ~$ S9 Y# {& K* }( _4 f! _' |- x5 R( Q: l
  e( z  {* X7 G2 @" D$ [7 J* q
PHP文件锁示例:
  1. /*; h, J9 W8 {# j
  2.     模拟秒杀活动-- 商品100件
    6 g0 o3 g8 @5 y8 ?! ~
  3.     CREATE TABLE ta; k% ^9 y" n% y. h
  4.     (/ z. g+ j4 q3 y
  5.         id int comment '模拟100件活动商品的数量'' B- {, H" D% i, d
  6.     );$ C: A  n/ n5 O( A( D: L) h* t# C
  7.     INSERT INTO ta VALUES(100);
    ; m3 U* s0 v6 w. S
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件+ x$ {7 ~0 C4 ]. u* S& r
  9.      */ 0 p1 Y% B' R- \+ D! T! D. S
  10.     9 N) e: v% d  A: g' ]! `( Y
  11.     // 关闭错误报告/ y8 L5 d1 a- a1 `; V! _. \
  12.      error_reporting(0); . P4 G" M2 W; K' p# F

  13. ! p, V/ r2 f' N( v" `3 |$ @6 \
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址, [) h. y- q% }7 G" Y4 }
  15.     $dbuser = 'root';            // mysql用户名) p) }0 x3 c# \6 y' D4 Q) S
  16.     $dbpass = 'root';          // mysql用户名密码
    3 c& \. H, k  |% K5 j9 B
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    + Z2 p, [) P: ^3 _
  18.     if(! $conn )2 C8 L4 A0 J% U. k2 A/ m3 H
  19.     {
    5 s$ k1 z% `1 H& a6 N$ Z& D$ ^  O! s
  20.         die('连接失败: ' . mysqli_error($conn));  R- v- a. G. a2 E- e" x1 F, U2 p
  21.     }
    4 g% g4 S" k' P7 Q( r
  22.     // 设置编码,防止中文乱码+ r, L$ l- Y. N. x- U
  23.     mysqli_query($conn , "set names utf8");# k0 x' H5 U/ |) `6 e. y
  24.     mysqli_select_db( $conn, 'temp' );
    3 L- \/ R3 R& c8 I1 ^
  25. 6 q7 x0 ^; [7 O& Q$ N
  26.     # php中的文件锁 7 g- t1 Z$ M' Y: W: z# ^; O
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    2 r. b3 o  C8 N& a) |
  28.     flock($fp, LOCK_EX);// 排他锁
    7 b& F, k: [! e6 u, }# y
  29. 9 B3 C) M- P, w2 Z" ]1 D
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    # w  G2 t: W& T7 O/ W
  31.     while($row = mysqli_fetch_assoc($retval))% H; L5 x5 ~! x5 r: c3 w1 z
  32.     {1 D. k" j& {: q8 S1 e/ B
  33.         $id =  $row['id'];9 v& p! [* X3 ^; W, e. ?
  34.     }! ?, ~$ k0 u6 b  D$ @  \
  35.     6 w. s! B. I' i
  36.     if($id > 0) % N% g* O9 I+ F" S* J) `# {
  37.     {
    3 P# P7 k$ {: @
  38.         --$id; 0 J6 k( P( ]1 q3 Z( {
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); $ ]+ l: _8 ~6 _+ k1 A9 S
  40.     } ) A- K! t) D! v0 n
  41.     # php的文件锁,释放锁 6 n" L. G$ G7 J2 G- B; F
  42.     flock($fp, LOCK_UN);
    * q8 @7 ^+ B8 Q' G# e, A1 y, ?  @/ ~
  43.     fclose($fp);+ r2 K9 L* _1 P" D  T

  44.   ?' m/ _  j0 o" r' R3 s
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ; L2 c& K/ g( ?# i- _* C% G
  46.     // while($row = mysqli_fetch_assoc($res))9 K( e* \( A2 _, m
  47.     // {
    , `; }* W! p- w
  48.     //     $id = $row['id'];0 f9 S' k/ t/ z" \
  49.     // }# A, b' x1 a, v
  50.     // echo $id;
复制代码
9 D9 [9 |4 d, L1 j
/ m# B# ^8 H- B  _$ N8 {
抢券活动实例:
  1. public function envelopeSnatching(){7 t6 K6 J% c; \" U% s, J
  2.         $lingqu = $_POST['type'];& l* z* p. @) _5 R4 P+ _! N
  3.         $uid=session('u_id');//用户id# Q9 q* h( S: ~* J8 q5 W
  4.         if(!$uid){
    3 l5 N# C  f( A8 _3 V
  5.             $data['msg']='您没登录,请先登录!';# x' Z% A( u7 r5 u
  6.         }else if(date('Y-m-d') != '2017-12-12'){% t4 H8 q4 f1 G& s6 S
  7.             $data['msg']='不在活动时间内!';
    , L8 W, |# p: P, i3 X6 E8 S$ `$ Q
  8.         }else{
    3 s2 C: w) M& `* i8 _& A
  9.             $hours=date('H');//当前小时数& x& J1 i/ C: [- |2 m  _
  10.             if($hours > '09' || $hours > '17'){4 m) ^5 Q0 K6 j) G
  11. + M: F% Z6 Q  ~1 f) _. B
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    2 q! [0 g0 t+ l3 D8 Y2 I
  13.                     if($lingqu == 1){
    9 I9 K& d) }# ?7 A0 `. N+ i
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过" u* j* x" _0 F1 j
  15.                         if($hours > '09'){9 A8 P. t2 }. t3 C, T1 K2 w
  16.                             $num=mt_rand(25,28);//优惠券金额  R( y0 ]3 q, `% p8 L
  17.                             $id=1;
    * D1 K7 E( P( x1 l
  18.                         }  Z/ t# O9 k, U  M! M& p: ]
  19.                     }else if($lingqu == 2){/ I5 z3 }  m$ q6 J3 c8 [- j
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    * Q" S* a; ]* Y  j
  21.                         if($hours > '17'){
    * E! Z- Q! h9 k
  22.                             $num=mt_rand(50,55);//优惠券金额
    3 n- H6 P: k% f: [
  23.                             $id=2;6 A+ I/ [! _4 A0 |- I+ b
  24.                         }
    0 J$ B" V8 ]3 t, p4 l6 N
  25.                     }
    ! e7 H4 ]6 G% {1 k% ^1 ]5 i6 w
  26.                     if(!$id){
      t! [  [' b! e
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    % u& Q+ Z$ K# E% L5 B' R
  28.                     }else{# l( g2 r$ ^# b( P' X
  29.                         if($is_lingqu){. t' i; z4 I% u9 h6 G6 O' |! R
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';( Z  U3 B6 J) h7 r3 T
  31.                         }else{2 T( A+ [4 `3 M% h' S% W" G6 U
  32.                             //锁表1 V8 A" D) Z8 V: h! z
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    ! p% f1 M; V4 n
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
      ^8 s8 [% W; S4 J
  35.                             if($active > 0){4 }7 ?2 O( S% [0 \
  36.                                 //开启事务/ q( u" ^5 L% q/ O' e  ]( i! F
  37.                                 M()->execute('start transaction');7 T; R" }+ {+ \8 W+ ^* b  p! y
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));* G- U) Z6 B1 v" }4 R. n! x. J
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    , g2 D* n& R' M: j$ u7 _# j, G
  40.                                 $members_preferential    =    M('members_preferential');
    9 d) y4 V* u2 y9 g8 x) P7 |/ V
  41.                                 //对应投资金额,! d/ g- M; p, N( n
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    " l! ?% _' {- `
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');/ ?: r; T* P1 f& Z/ C
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间) x6 m4 a: E& U/ ]* u: t& R
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    ) `- `" d/ B! V3 _8 F% d1 w) I
  46.                                 if($save && $add && $add2){
    ) u8 N( ]' t3 a5 u% N7 x
  47.                                     //事务提交1 \6 p* F5 c" K
  48.                                     M()->execute('commit');
    ) D+ L$ d2 R: E
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    + Q2 i5 j: c# O% q* F, V( ?7 A% n
  50.                                 }else{% k1 w( D; q7 Q2 W. K  S
  51.                                     //回滚
    8 E& W6 K- P) c7 S0 d/ ?
  52.                                     M()->execute('rollback');
    1 z4 v5 B! p2 R9 k1 v
  53.                                     $data['msg']='未知错误!';( M4 n- ^) u6 `& }$ Q
  54.                                 }
    # V0 E* z* O; t5 K; ~
  55.                             }else{3 W2 }$ x0 O' p. U, k; N
  56.                                 $data['msg']='红包已领完,你来晚了!';9 V- W3 D! D7 k) f/ G( |/ Q9 b
  57.                             }
    5 W# O  p) Z7 U1 v
  58.                             M()->execute('UNLOCK TABLES');$ \  \: O6 Z& S" l& |; ^
  59.                         }
    2 n9 W" t) v5 i/ k
  60.                     }" u# K: a" Y5 ~3 k5 Y, Y
  61.                 }else{3 b, g9 z$ N/ o5 M
  62.                     $data['msg']='非法操作!';0 _% Q( Z6 |/ i( X8 g: F( W
  63.                 }( G  R! k/ Y1 j: J
  64.             }else{
    & G# u( E2 k9 b# D9 p' H: P' K
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    % [( \6 h1 Y, E
  66.             }, i( |$ [: [, S# v( l, b
  67.         }: \  x: K1 s- N) B) U' Q
  68.         exit(json_encode($data));
    8 t' k) |1 O8 A
  69.     }
复制代码
. f9 @( |, B) U" p: ~3 x

0 u7 ]: q) T' {1 I/ h, {
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2025-2-5 19:50 , Processed in 0.114854 second(s), 19 queries .

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