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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

) @" t; b( L2 m, A) B/ f
Mysql中的锁语法:( l3 f- W* g9 y. e) h. c) p, D
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】4 |# ]1 U1 Q" \& }
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
% G: ?: ?6 F% e0 f- A! GWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
( `4 E# d* v3 P, l4 J- }! k# p注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :% \$ g; I2 b% e& s4 h& G
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
' k$ k7 `/ C4 ~0 l2 w测试时,有个文件就行,叫什么名无所谓
总结:* y# H) Q8 _" \8 u, J& H
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
7 @  D! m9 p4 x8 `, V  u1. 高并发下单时,减库存量时要加锁
0 \* ~7 }6 r2 m7 L/ {9 B  K6 z( ^1 ^2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    ) N6 n+ ?1 ?2 c% T
  2.     模拟秒杀活动-- 商品100件* d9 `* Q. S! n" I( Y5 X, Y' r
  3.     CREATE TABLE ta1 M2 V; p1 G6 c( S" G: q
  4.     (
    ; Q& c3 c; Z$ a" Q# F& r8 ^6 C
  5.         id int comment '模拟100件活动商品的数量'! l& A5 `2 I& ]" W3 K, W
  6.     );
    $ q7 n( ?8 f, ^# D* c% g
  7.     INSERT INTO ta VALUES(100);% O' D1 _5 O, v0 t
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件. l0 T; j* p: b8 V* w7 y1 D* [
  9.      */ ) V( Y4 ^9 ^8 v7 v# H
  10.     3 A; _$ w4 p) a" Q: {" p/ o
  11.     // 关闭错误报告
    2 v+ ^1 `" O. w9 T
  12.      error_reporting(0); 8 E" `2 a( M: k/ \6 j% n# k3 c, N

  13. 7 Z- r5 V: G; r3 r! k2 W$ E
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    . Y( d. |, o3 Z' n/ e
  15.     $dbuser = 'root';            // mysql用户名
    7 f) y9 X, q% V8 L
  16.     $dbpass = 'root';          // mysql用户名密码  m/ j- l& Z4 _, Q' ~- ~. c
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);3 b+ H- B; O% f  x
  18.     if(! $conn )4 U8 j! R- K5 {/ d! o
  19.     {& ^* X" x9 Y. }9 w$ D+ K- E$ h
  20.         die('连接失败: ' . mysqli_error($conn));
    : |* ]8 J+ R% l/ d( O+ b
  21.     }
    - `' H3 j; i1 q' w/ i+ [, X
  22.     // 设置编码,防止中文乱码1 ]9 w9 N& ]8 m: o* i
  23.     mysqli_query($conn , "set names utf8");
    # s; {( `; R6 m" ^7 u# ?
  24.     mysqli_select_db( $conn, 'temp' );
    / p% K( C  J) L2 W) z! ]: B

  25. ' D/ m7 u- x3 F6 a* p* V3 @/ b, B- g: J
  26.     # mysql 锁
      M) m' w6 M! n. F+ u1 ]6 y* R
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 % {5 W0 |7 u4 J! ~* I
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    ! f* E% L( l, [# v
  29.     $id = mysqli_result($rs, 0, 0); 0 p6 w% b+ t: c1 S: N% i, S
  30.     if($id > 0) : ]/ M. R4 J: J0 u+ v- E) p* {+ k
  31.     {
    3 c; Y9 E( y+ I! z3 O  x9 X% p6 T
  32.         --$id;
    4 ?" T$ {5 T' h/ y+ m
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    % T4 i; U! x- Z& W- ^! N+ c
  34.     } 3 F$ \7 U5 }" k7 W0 o

  35. 9 @( \, w! ~0 k( Z4 [! s! `
  36.     # mysql 解锁 ) q5 D3 M5 Z( A, L, ~
  37.     mysqli_query($conn , 'UNLOCK TABLES');( s* C$ R( j5 O# R
  38.     //查询解锁后的id值
    : [, D/ M+ K9 t3 l) }
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    + \4 X  [. [5 F3 i
  40.     // while($row = mysqli_fetch_assoc($res))
    " o2 \) I8 z6 Z0 Z
  41.     // {
    ) c) Y+ B# x) E1 y: W
  42.     //     $id = $row['id'];3 Q- X  z& E  ~! o+ E( Q! |7 `
  43.     // }
    2 M4 ?7 N9 x: C7 G, T2 X0 q
  44.     // echo $id;
复制代码

$ m" ~" h& m4 o1 U2 X8 ?6 K, j1 A- f2 t

5 r" p9 S# _- r( O2 E) a8 g
PHP文件锁示例:
  1. /*; z" |) V% f8 Z$ X5 A9 ~
  2.     模拟秒杀活动-- 商品100件
    $ O" T6 q, B7 N3 D
  3.     CREATE TABLE ta
    , j+ q5 G1 O8 z* x8 s
  4.     (9 k0 A( V3 L. C9 |
  5.         id int comment '模拟100件活动商品的数量'
    / l5 i% j  \' C  G9 E0 K
  6.     );1 C3 @  s& A/ X) R
  7.     INSERT INTO ta VALUES(100);- L3 M, }9 \. z, m; i" D
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件  t# i$ \' m6 C0 o0 O
  9.      */
    , I$ v7 _, V: M0 |; @1 s+ F
  10.     ( T: w4 _% N$ ^( R& b( c. K9 k$ o
  11.     // 关闭错误报告
    ! u1 H9 ?  g2 [, o5 S- P
  12.      error_reporting(0);
    # ?4 X; Z5 p% M7 e

  13. ) B% j8 B. K# F. l
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址9 ]) D  ^' t' Q+ f( g- n- x9 Y1 S) i
  15.     $dbuser = 'root';            // mysql用户名
    ; e0 ]/ `  A5 _: `  l0 E* Z; S4 Q
  16.     $dbpass = 'root';          // mysql用户名密码' B. r$ s5 R" }7 O
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);$ T( N1 o* x9 R% X5 W$ w
  18.     if(! $conn )
    ) k7 N' O+ b0 ^. h* k, w
  19.     {4 A% N& O' e, t: w& `$ e
  20.         die('连接失败: ' . mysqli_error($conn));+ Q8 a1 C8 I8 a. q6 K: z
  21.     }
    . v  `7 Q( T- p
  22.     // 设置编码,防止中文乱码
    5 l1 M  o$ o9 t
  23.     mysqli_query($conn , "set names utf8");8 ?* n, \; X, h% _4 T; r: `
  24.     mysqli_select_db( $conn, 'temp' );
    ) }/ ?" h% m3 p- Q6 I9 F

  25. , T2 r( w* K- E
  26.     # php中的文件锁 7 W9 e8 _8 Y% X' X7 P
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 - i+ K7 x! P' T$ s$ |
  28.     flock($fp, LOCK_EX);// 排他锁
    ' J6 `( E8 l. ]1 a8 E2 A
  29. - H6 k( `6 q* m4 J+ n8 i$ G
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 2 t* v" }$ X& p- S9 l
  31.     while($row = mysqli_fetch_assoc($retval))
    7 ]1 {9 W: P- o
  32.     {
    % @9 y& p8 W( ^' P1 K6 t& \; }0 c
  33.         $id =  $row['id'];% y' k8 k7 ?2 G% Z
  34.     }
    ! Q( \9 X' T- E3 p: o# f
  35.    
    3 |  J$ F, ^9 A3 H
  36.     if($id > 0) 4 q: q1 E1 U  y- H. @2 m
  37.     {
    2 q. ^6 o& }( I* ]. J, M
  38.         --$id; $ n  |# I% E! ?' E/ X1 m+ _9 D) V5 d
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    7 B1 S% c7 N8 ~/ `$ M
  40.     } & I  e# F  a* v6 q9 l- [# D
  41.     # php的文件锁,释放锁
    $ a* d. k4 t5 L; U  n1 v  J8 p
  42.     flock($fp, LOCK_UN); 3 u* P( U8 p1 Q! G! D- }
  43.     fclose($fp);) l/ C  H7 v& h& z8 i  e
  44. ' M+ {# u' Q" J5 e. A6 O
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ( m. d: u2 w* k4 R
  46.     // while($row = mysqli_fetch_assoc($res))
    3 E; l' k9 n  f- Z  q7 ~1 x3 v
  47.     // {
    ; @  `( D' D8 y5 Z4 N# A
  48.     //     $id = $row['id'];
    * u* \8 X2 V6 p, h
  49.     // }" b8 o$ z1 G$ a9 p  n& x& E" A
  50.     // echo $id;
复制代码

* q4 [, X& f" Z) {; J9 A3 z
+ C7 {7 V# u/ c* T% \; ^8 r
抢券活动实例:
  1. public function envelopeSnatching(){
    ( [( V7 X, |( p2 j
  2.         $lingqu = $_POST['type'];+ P# b9 x) |6 y
  3.         $uid=session('u_id');//用户id
    ( ?/ C9 d2 O9 X0 N; |8 B8 R
  4.         if(!$uid){: g# y7 Z7 k" u
  5.             $data['msg']='您没登录,请先登录!';
    * r4 T+ j# w. `0 o7 P/ j3 x! `; W
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    9 g9 ?# I1 K7 }( H1 Z' G
  7.             $data['msg']='不在活动时间内!';
    . d% X+ f7 z) F# a% t8 v+ u! l
  8.         }else{6 i# d6 f/ _0 n' I+ x
  9.             $hours=date('H');//当前小时数# Y1 k4 |3 |: X6 b0 O
  10.             if($hours > '09' || $hours > '17'){
    & S% z) c2 L8 L! x/ h% |, l

  11. . [6 w  m4 o3 A) v4 m' b
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    8 n( J1 m2 s( n( F6 m5 X: b/ M% L& d
  13.                     if($lingqu == 1){
    * w5 a, q5 {4 @3 i# A5 f+ O  m& o
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过- E+ v/ O2 e3 v
  15.                         if($hours > '09'){5 `4 w. R8 S+ `) t+ [
  16.                             $num=mt_rand(25,28);//优惠券金额
    * _: k# ^# w" @) H. I
  17.                             $id=1;
    2 A& L! H6 i, P; X/ [! H. P8 L
  18.                         }" R( K9 R4 d6 |- e
  19.                     }else if($lingqu == 2){5 c- }2 a* R% o" A) o- u
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    5 X& Z+ s. F) O
  21.                         if($hours > '17'){/ V( K# O, ]+ U4 `' Y- ^
  22.                             $num=mt_rand(50,55);//优惠券金额
    ) C1 Q9 @/ _2 L" v' ?) o
  23.                             $id=2;
    5 D' B9 i0 l$ p; B1 m
  24.                         }* C4 F0 e! G* h
  25.                     }7 d7 J2 y1 a# L, q) z, Q
  26.                     if(!$id){
    ! [: b( i( }% M( U3 N! R) o
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    * w- H- _/ a4 i2 C' r+ e
  28.                     }else{% O) l  r$ f+ O8 p% e9 B6 K
  29.                         if($is_lingqu){2 c! c& E+ ^; ]1 X, d( g/ C
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    3 m% J9 R* ~0 b! i7 ~; A7 d4 Z$ `
  31.                         }else{
    - J3 d# t1 J$ h& P$ X
  32.                             //锁表
    & K' \/ s0 Q) @: \1 {, r
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');6 B# u- [5 v, k  B; \
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    % y/ `. _1 v! P, x1 O+ Y! V/ J9 [9 W
  35.                             if($active > 0){1 Y* o, w& t" T; d$ W2 B! S# Z/ C+ X
  36.                                 //开启事务
      d$ J$ K3 N( S. s
  37.                                 M()->execute('start transaction');
    : e- b; j' a. G
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));4 D: h( J; c7 P: y
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    ' J' h+ A. x5 P3 f9 `4 e' N
  40.                                 $members_preferential    =    M('members_preferential');
    " r' ^  I+ p9 V
  41.                                 //对应投资金额,% A& e* H* P6 f# V
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));6 h% b' C: s+ X0 _! E  H9 n
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');+ J+ P2 [- c8 ^% n/ p3 q
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    : r! `) z; A& [) j) M
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    - l% T7 @9 K+ n9 U  _
  46.                                 if($save && $add && $add2){% W2 O1 ^. A( W+ \9 x/ F& \0 j+ T
  47.                                     //事务提交
    9 Q' W& R- c) I0 v
  48.                                     M()->execute('commit');; T' o, P% `+ o. V3 Y' ?6 @+ c
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';  q! H% z% e7 o+ Y) N/ V4 P. \
  50.                                 }else{8 M% ?5 }, t/ k. ]5 c' T! X7 j( g
  51.                                     //回滚
    1 l: U  }. E8 }# R+ z7 Y
  52.                                     M()->execute('rollback');+ P0 f# f1 H  A. j
  53.                                     $data['msg']='未知错误!';
    5 I$ c& n+ a" |+ t8 i1 S
  54.                                 }; Y# o; K0 z6 M, T+ ~, T
  55.                             }else{: `( @8 z9 B( c! I4 P
  56.                                 $data['msg']='红包已领完,你来晚了!';
    * C8 v* N( S1 u  O8 j
  57.                             }. J1 j  r- b6 h, E; ~
  58.                             M()->execute('UNLOCK TABLES');
    9 o$ h3 r. ]) o- h5 g1 K' T  B
  59.                         }
    ! z$ u" |/ R" W4 |  |
  60.                     }
    8 @, I9 g" T: E* C
  61.                 }else{, H( x- v! K, ]5 m/ H1 [8 ~
  62.                     $data['msg']='非法操作!';
    : j5 j, N2 L, k
  63.                 }0 K5 I# I& T/ x9 q, T
  64.             }else{
    5 m3 D6 Y$ [0 |% U' x
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ( }" s' y- b' ~% Y. ]
  66.             }5 d) s$ \! O# B' A
  67.         }& V' C+ C/ d# g" D# h; P
  68.         exit(json_encode($data));
    # S0 v' ^9 h! U. z
  69.     }
复制代码
. ]5 G! o; r. y
: E8 p; W$ N7 }
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 15:24 , Processed in 0.056750 second(s), 22 queries .

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