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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 5741|回复: 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://请求的脚本
复制代码
: X# ]0 n. c) s: k* a  F, u$ }
Mysql中的锁语法:0 i; a# p, X# m% Z
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】" Q8 O( w; b3 t8 p5 J
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表9 v6 V$ ?4 x; [& @' ^* A' l
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
/ n, k8 R1 ~4 {3 q: w  H注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
- P3 n* d! D  x文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。% B; Z# N2 m0 T0 w: P* ]7 H
测试时,有个文件就行,叫什么名无所谓
总结:( V, H+ C: L/ q; ]8 |: P
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:( R1 I+ Y* q5 \2 {4 X. a
1. 高并发下单时,减库存量时要加锁; ]/ d6 f' R; _7 o
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*+ Q) ^% v% y% X
  2.     模拟秒杀活动-- 商品100件
    7 L- _( e  z) X, d8 e2 Z: |* F
  3.     CREATE TABLE ta! h" f( h6 p1 H& s; [
  4.     (0 x0 j3 h9 r$ S) j$ o& J
  5.         id int comment '模拟100件活动商品的数量'( k* P8 g  h5 m  a+ O4 q
  6.     );" T/ J7 z! f4 Q/ Q
  7.     INSERT INTO ta VALUES(100);) n5 p2 h6 J. n3 z% c0 H, |$ H
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    7 a# C  a2 l4 R$ R! i/ k- O
  9.      */ 6 Y1 }" k) E" f# m
  10.     " G3 H" q" T) r) |8 K. ^
  11.     // 关闭错误报告4 p4 ^, g1 \4 V
  12.      error_reporting(0); ( B) U) h$ }+ j+ G8 Z2 N3 B, S- @

  13. " e  ~) f/ e' K9 u
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    3 u# G: ?' `3 F, f% O% E
  15.     $dbuser = 'root';            // mysql用户名8 s/ ?) h% F. i; ^
  16.     $dbpass = 'root';          // mysql用户名密码
    $ C4 D% z5 k; G1 P7 D
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);1 x" {: m) m( L
  18.     if(! $conn )# @4 `6 e$ ^6 f8 s
  19.     {$ s% e6 E- o/ ^: x
  20.         die('连接失败: ' . mysqli_error($conn));5 E2 t  |7 M! A* Y5 f' C
  21.     }
    - q: T2 a8 v. j3 \. I# ?# X
  22.     // 设置编码,防止中文乱码
    ! p  T/ u" Z( P! h' {+ {5 V9 h! Q8 k
  23.     mysqli_query($conn , "set names utf8");  V$ O/ y) s' |5 @; s( K' p, O7 Q
  24.     mysqli_select_db( $conn, 'temp' ); ; S: f7 N+ G  M4 q. }

  25. # s% Z- T) l3 c$ a/ o: ~) K
  26.     # mysql 锁 ! Z# h0 C% I2 l
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 % I$ W4 U- G! j3 \% p% c4 q
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 7 ?" V1 s3 m' B0 G$ G
  29.     $id = mysqli_result($rs, 0, 0);
    " R5 ~6 H: G! q1 A0 j0 W/ S
  30.     if($id > 0) 5 b* o& |4 E' _) b1 T! [" Q9 ?& [
  31.     { 8 s' z* T1 Q1 ~
  32.         --$id;
    " I" Z; C5 y& H4 U7 m. c1 m/ d
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    - M) }) J0 ^/ y+ k$ {- I$ d8 C
  34.     }
    6 V8 s* `/ j6 V8 a& s" {4 _

  35. . l9 f% g8 c  ?! e5 c9 C
  36.     # mysql 解锁 ; J- `+ _& {3 p
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    4 q8 I- m3 D. {4 l6 B
  38.     //查询解锁后的id值5 f8 p1 }# c! h) k# D& H& x: K; H. P
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');# F6 u6 v" n9 _4 }0 f
  40.     // while($row = mysqli_fetch_assoc($res))
    6 [+ A4 t' J" h; y$ O% V9 `
  41.     // {1 {6 V, P/ b/ {& w) w; G9 h
  42.     //     $id = $row['id'];
    ; K& P% W0 A% U9 Y* A. S) W9 Y7 B
  43.     // }9 [& i" b$ w% B: F6 G
  44.     // echo $id;
复制代码

" ]2 |8 E- w1 R$ ?, L5 n5 G0 c3 G7 G. r
" }/ l( A3 T4 A" F  Q$ Z4 K
PHP文件锁示例:
  1. /*
    & \9 \% ?' L& k5 ?& J
  2.     模拟秒杀活动-- 商品100件+ ^% e& M- H7 m1 l6 X. ~0 f/ c
  3.     CREATE TABLE ta$ q/ j9 D: j* F2 }- E  v( @  i! i- ^' k
  4.     (! @# ?# h2 q0 V+ Q
  5.         id int comment '模拟100件活动商品的数量'
    " I6 A& d5 T: j4 T# T9 ]
  6.     );) T0 Y, R: F# |3 R
  7.     INSERT INTO ta VALUES(100);
    ( R: h2 s2 V% u9 b
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    9 }+ S0 K3 N" Y
  9.      */
    7 A1 _1 F# [0 `# @) T& E
  10.     / e. U9 Y( t# Y- _4 ]  W; A6 m
  11.     // 关闭错误报告
    2 t3 G9 l8 t) }" x1 u+ v; w. V
  12.      error_reporting(0);
    ' B9 U; {' p5 u, `9 x* s
  13. ' M1 p) w5 D# ]+ g3 i* e
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* b# U9 }( k- e6 c1 H3 m- J3 \
  15.     $dbuser = 'root';            // mysql用户名
    9 n, [' D, N/ U9 i: d! z
  16.     $dbpass = 'root';          // mysql用户名密码
    ! ?& A7 r. N' _; R9 w2 W
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);8 d% {, I! i" c3 R5 Y: i4 p
  18.     if(! $conn )
    - G$ W! P% A  ~5 {4 F- W
  19.     {
    . T% i. }- V: ]/ m* T9 l) `( {
  20.         die('连接失败: ' . mysqli_error($conn));
    4 a$ q* q. ~/ b0 V: k5 p) ^3 X
  21.     }, k) }5 y, G8 p& Q9 k5 o! S
  22.     // 设置编码,防止中文乱码
    * U( w2 q, a  k. o2 ~; _8 B, ?
  23.     mysqli_query($conn , "set names utf8");5 e* C/ ^% @' _/ E$ }) K+ m
  24.     mysqli_select_db( $conn, 'temp' ); , @3 m1 o- u6 W0 Z' e, z" M
  25. 4 K& O; K1 U6 D* h4 ~
  26.     # php中的文件锁
    * y2 @) b' p% b4 u5 X
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 : ~- H% p1 g0 ~+ j
  28.     flock($fp, LOCK_EX);// 排他锁 2 M- U% S, l( r6 e5 K- b5 s, W9 z
  29. ; h$ {% M# \( }
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    6 v; {( t% r( c4 B! I
  31.     while($row = mysqli_fetch_assoc($retval))  T  P, \. I* [
  32.     {4 W, k( T, _) i3 K6 y8 J
  33.         $id =  $row['id'];
    3 W2 d9 t0 B) a
  34.     }) ]7 x5 r* A" M* x
  35.    
    # Q' [, b( D0 ]8 R: ^, A( @
  36.     if($id > 0) 0 R3 b+ A, J9 b6 U
  37.     { $ h- `) O/ q# O
  38.         --$id;
    3 ~7 U9 i0 s. d( h" S* q2 o5 {; B7 ^
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    0 }# T# ^  Z5 x( Q  S& N( }- I
  40.     }
    / n0 X5 Y- [7 _
  41.     # php的文件锁,释放锁 " d; g1 f4 ?0 U* i/ @
  42.     flock($fp, LOCK_UN); % R  O: L2 W- d
  43.     fclose($fp);7 i7 J$ U; o- }& w- o

  44. $ s+ O3 u& p9 v
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    # p+ }" `; i. A; `* W2 b2 s
  46.     // while($row = mysqli_fetch_assoc($res))
    3 J3 M9 F% C" `2 W4 p4 ]* ]5 \2 h
  47.     // {2 o- u" ]  q" n) v7 O6 s7 t
  48.     //     $id = $row['id'];* ]' k4 u& E1 b- ^5 r8 Q0 H
  49.     // }" o4 b; t7 e# h7 ~$ U4 ?6 m
  50.     // echo $id;
复制代码
# X3 I  \! S9 v& t% J  A: `  p

) `2 P0 s% O' ?2 \9 e# [
抢券活动实例:
  1. public function envelopeSnatching(){
    . j( v0 o* _, h0 ~. M* p; b
  2.         $lingqu = $_POST['type'];: t! {; R4 _1 q' W
  3.         $uid=session('u_id');//用户id
    , k" v8 j$ n, D+ C
  4.         if(!$uid){
    3 G: d* e* j: b8 ^
  5.             $data['msg']='您没登录,请先登录!';
    ) s, I; K5 `. g4 J
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    1 V% |7 R) ~9 y3 b1 h
  7.             $data['msg']='不在活动时间内!';; V2 o; B% S2 Z/ y
  8.         }else{
    ; |' j# P9 x; `+ F3 E0 m' ^
  9.             $hours=date('H');//当前小时数
    $ A2 ]# I4 ]% ]; E3 W
  10.             if($hours > '09' || $hours > '17'){/ t& ~/ u( Q  h8 D& q. ^
  11. # a0 E1 h* n  u" G8 ?; K2 p
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的! T/ C% t/ I' B0 x5 S6 V0 d. M
  13.                     if($lingqu == 1){/ W. G4 G/ N) ~, B
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    $ L1 S3 Y+ z6 E) d- O
  15.                         if($hours > '09'){7 h% {- ?; p; b. z) A* S* N& U
  16.                             $num=mt_rand(25,28);//优惠券金额
    0 O% k+ q- Y0 {( N8 M. e: ?% g5 {
  17.                             $id=1;
      ]% u- h& R& g/ I8 ?+ _! J& L3 |
  18.                         }, @4 H. T! O9 a% v+ J4 k
  19.                     }else if($lingqu == 2){
    8 ^1 F. ]! q+ b6 K* g
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();# _0 S" a  I9 L7 k2 t& n# {; n
  21.                         if($hours > '17'){
    9 c1 X$ V/ p4 s5 C- a
  22.                             $num=mt_rand(50,55);//优惠券金额
    + P( d0 ^5 S* b1 W, R; R( t
  23.                             $id=2;( u# L) `! e3 [1 I
  24.                         }
    * I3 y# M, S* M/ {& U0 u- y
  25.                     }6 I" T# p$ h4 }+ n( J
  26.                     if(!$id){& I7 B" \# d  _( x/ b
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    ) S% v: L; ^& N8 ]9 _( |
  28.                     }else{
    " ?6 X* T) N9 v. G, n
  29.                         if($is_lingqu){
    8 A4 _8 \1 h  `
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';" U: X7 M- B- U; N6 t7 \
  31.                         }else{
    , \; ^5 V3 ^' R8 \) A8 X# ]
  32.                             //锁表
    / a7 ^0 h, R* `2 |
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');) X- V  e' K5 V3 K/ K# f$ i) s
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();, b" l4 z& t  t" c8 T4 w, S* d
  35.                             if($active > 0){% I0 X9 l& K0 N3 u
  36.                                 //开启事务
    * E/ @$ j& t8 h1 F4 B* W
  37.                                 M()->execute('start transaction');
    1 _' M. c$ F- C3 b
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    4 w) p/ g2 r; Q# A
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
    8 A) R- v- q0 [: e
  40.                                 $members_preferential    =    M('members_preferential');- K3 d3 F( F: h8 d8 @% p. _
  41.                                 //对应投资金额,; O/ _$ D; ]# f* m, n" b
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));; ?* v8 X) `4 ~. Q( I$ i( I& b( j
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');% U* Y! \& N# Q' j4 z: N# m2 w4 E8 {/ \
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    9 k$ c8 A- E. z; I/ J
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券& n5 u( ?3 W( W
  46.                                 if($save && $add && $add2){/ \$ ^& W8 @$ G. }" [6 `& [/ j
  47.                                     //事务提交
    : S& C0 c: L. B
  48.                                     M()->execute('commit');/ A, x9 d0 M( ^2 \/ z
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    : u) U' J; w- H$ r, k; P. b# l
  50.                                 }else{  d, N, I* F5 P" |
  51.                                     //回滚
    9 ]6 g/ ~' V7 D5 l( m. ?% L% |% g5 T
  52.                                     M()->execute('rollback');! L( k1 n* u9 T! y
  53.                                     $data['msg']='未知错误!';
    ! r+ W% \! d) i( ~  t" ^( U
  54.                                 }% C" \6 O; y% x  d/ h' j. s6 ]: [
  55.                             }else{5 S2 z) s5 k7 v! V0 B3 ]7 B# M5 C5 C
  56.                                 $data['msg']='红包已领完,你来晚了!';
    . r) {8 Z4 i4 Q( E' j0 t  }  z
  57.                             }
    2 M2 T6 a( Y$ R& l
  58.                             M()->execute('UNLOCK TABLES');
    . y! g1 O$ @3 E; v
  59.                         }
    % J- v; h4 P( P( }7 x8 m2 M: z5 U
  60.                     }2 X3 d3 B7 I/ F
  61.                 }else{
    / T3 p6 Q: E  h( E
  62.                     $data['msg']='非法操作!';" X  Z2 q" T, }" _1 _( b" p
  63.                 }9 H# Q  S4 j; k4 M
  64.             }else{
    % _8 `/ b2 N7 O# @* P& E1 X
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    6 W& @, Q' k0 F
  66.             }
    ' x  O$ Z" w8 r" h4 _
  67.         }  L2 G/ o; S0 k7 E
  68.         exit(json_encode($data));1 M6 J3 g2 F2 [2 a6 i7 G
  69.     }
复制代码
) R! ]* f; M, u0 O: G7 P
4 t& U) K. [9 S% g# D- E
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 16:28 , Processed in 0.109590 second(s), 20 queries .

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